Class: Analysand::ViewStreaming::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/analysand/view_streaming/builder.rb

Overview

Private: A wrapper around JSON::Stream::Parser that extracts data from a CouchDB view document.

Defined Under Namespace

Classes: ObjectNode

Constant Summary collapse

CALLBACK_METHODS =

JSON::Stream::Parser callback methods.

%w(
  start_object end_object start_array end_array key value
)
KNOWN_KEYS =

If we find a key in the toplevel view object that isn’t one of these, we raise UnexpectedViewKey.

%w(
  total_rows offset rows
)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBuilder

Returns a new instance of Builder.



27
28
29
30
31
32
33
34
# File 'lib/analysand/view_streaming/builder.rb', line 27

def initialize
  @in_rows = false
  @parser = JSON::Stream::Parser.new
  @stack = []
  @staged_rows = []

  CALLBACK_METHODS.each { |name| @parser.send(name, &method(name)) }
end

Instance Attribute Details

#offsetObject (readonly)

Returns the value of attribute offset.



9
10
11
# File 'lib/analysand/view_streaming/builder.rb', line 9

def offset
  @offset
end

#staged_rowsObject (readonly)

Rows constructed by the JSON parser that are ready for StreamingViewResponse#each.



14
15
16
# File 'lib/analysand/view_streaming/builder.rb', line 14

def staged_rows
  @staged_rows
end

#total_rowsObject (readonly)

Returns the value of attribute total_rows.



10
11
12
# File 'lib/analysand/view_streaming/builder.rb', line 10

def total_rows
  @total_rows
end

Instance Method Details

#<<(data) ⇒ Object



36
37
38
# File 'lib/analysand/view_streaming/builder.rb', line 36

def <<(data)
  @parser << data
end

#check_toplevel_key_validity(k) ⇒ Object



115
116
117
118
119
# File 'lib/analysand/view_streaming/builder.rb', line 115

def check_toplevel_key_validity(k)
  if !KNOWN_KEYS.include?(k)
    raise UnexpectedViewKey, "Unexpected key #{k} in top-level view object"
  end
end

#end_arrayObject



81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/analysand/view_streaming/builder.rb', line 81

def end_array
  if @in_rows
    obj = @stack.pop

    # If there's nothing on the row stack, it means that we've hit the
    # end of the rows array.
    if @stack.empty?
      @in_rows = false
    else
      @stack.last << obj
    end
  end
end

#end_objectObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/analysand/view_streaming/builder.rb', line 48

def end_object
  if @in_rows
    # If the stack's empty and we've come to the end of an object, assume
    # we've exited the rows key.  Trailing keys are handled by
    # check_toplevel_key_validity.
    if @stack.empty?
      @in_rows = false
    else
      obj = @stack.pop.to_object

      # If obj was the only thing on the stack and we're processing rows,
      # then we've completed an object and need to stage it for the
      # object stream.
      if @stack.empty?
        staged_rows << obj
      else
        @stack.last << obj
      end
    end
  end
end

#key(k) ⇒ Object



95
96
97
98
99
100
101
102
# File 'lib/analysand/view_streaming/builder.rb', line 95

def key(k)
  if !@in_rows
    check_toplevel_key_validity(k)
    @stack.push k
  else
    @stack.last << k
  end
end

#start_arrayObject



70
71
72
73
74
75
76
77
78
79
# File 'lib/analysand/view_streaming/builder.rb', line 70

def start_array
  # If we're not in the rows array but "rows" was the last key we've
  # seen, then we're entering the rows array.  Otherwise, we're building
  # an array in a row.
  if !@in_rows && @stack.pop == 'rows'
    @in_rows = true
  elsif @in_rows
    @stack.push []
  end
end

#start_objectObject



40
41
42
43
44
45
46
# File 'lib/analysand/view_streaming/builder.rb', line 40

def start_object
  # We don't need to do anything for the toplevel view object, so just
  # focus on the objects in rows.
  if @in_rows
    @stack.push ObjectNode.new
  end
end

#value(v) ⇒ Object



104
105
106
107
108
109
110
111
112
113
# File 'lib/analysand/view_streaming/builder.rb', line 104

def value(v)
  if !@in_rows
    case @stack.pop
    when 'total_rows'; @total_rows = v
    when 'offset'; @offset = v
    end
  else
    @stack.last << v
  end
end