jnunemaker-siren 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,162 @@
1
+ grammar JsonQuery
2
+ rule expression
3
+ additive / multiplicative / atom
4
+ end
5
+
6
+ rule query
7
+ identifier filter* <Query>
8
+ end
9
+
10
+ rule identifier
11
+ (root / current / symbol) <Identifier>
12
+ end
13
+
14
+ rule root
15
+ "$" <Root>
16
+ end
17
+
18
+ rule current
19
+ "@" <Current>
20
+ end
21
+
22
+ rule symbol
23
+ [A-Za-z$_] [A-Za-z0-9$_]* <Symbol>
24
+ end
25
+
26
+ rule filter
27
+ (field_access / boolean_filter / map_filter / sort_filter) <Filter>
28
+ end
29
+
30
+ rule field_access
31
+ ("." (symbol / all) / "[" (field_access_expression / all) "]") <FieldAccess>
32
+ end
33
+
34
+ rule field_access_expression
35
+ first:expression others:("," expression)* <FieldAccessExpression>
36
+ end
37
+
38
+ rule all
39
+ "*" <AllFilter>
40
+ end
41
+
42
+ rule boolean_filter
43
+ "[?" boolean_expression "]" <BooleanFilter>
44
+ end
45
+
46
+ rule map_filter
47
+ "[=" expression "]" <MapFilter>
48
+ end
49
+
50
+ rule sort_filter
51
+ "[" sorter expression "]" <SortFilter>
52
+ end
53
+
54
+ rule sorter
55
+ space ("/" / "\\") space <Sorter>
56
+ end
57
+
58
+ rule boolean_expression
59
+ or_expression / and_expression / boolean_atom
60
+ end
61
+
62
+ rule or_expression
63
+ first:and_expression "|" second:or_expression <Or> / and_expression
64
+ end
65
+
66
+ rule and_expression
67
+ first:boolean_atom "&" second:and_expression <And> / boolean_atom
68
+ end
69
+
70
+ rule boolean_atom
71
+ space ("(" boolean_expression ")" / first:expression comparator second:expression) space <BooleanAtom>
72
+ end
73
+
74
+ rule additive
75
+ first:multiplicative operator:(add / subtract) second:additive <Additive> / multiplicative
76
+ end
77
+
78
+ rule multiplicative
79
+ first:atom operator:(times / divide) second:multiplicative <Multiplicative> / atom
80
+ end
81
+
82
+ rule atom
83
+ space ("(" expression ")" / query / number / string / boolean / null) space <Atom>
84
+ end
85
+
86
+ rule times
87
+ "*" <Multiplication>
88
+ end
89
+
90
+ rule divide
91
+ "/" <Division>
92
+ end
93
+
94
+ rule add
95
+ "+" <Addition>
96
+ end
97
+
98
+ rule subtract
99
+ "-" <Subtraction>
100
+ end
101
+
102
+ rule comparator
103
+ (not_equal / lte / gte / equal / lt / gt) <Comparator>
104
+ end
105
+
106
+ rule equal
107
+ "=" <Equal>
108
+ end
109
+
110
+ rule not_equal
111
+ "!=" <NotEqual>
112
+ end
113
+
114
+ rule lt
115
+ "<" <LessThan>
116
+ end
117
+
118
+ rule lte
119
+ "<=" <LessThanOrEqual>
120
+ end
121
+
122
+ rule gt
123
+ ">" <GreaterThan>
124
+ end
125
+
126
+ rule gte
127
+ ">=" <GreaterThanOrEqual>
128
+ end
129
+
130
+ rule string
131
+ "'" ('\\' ("'" / '\\' / '/' / 'b' / 'f' / 'n' / 'r' / 't' / 'u' hex hex hex hex) / [^\'\\])* "'" <String>
132
+ end
133
+
134
+ rule number
135
+ "-"? ("0" / [1-9] digit*) ("." digit+)? ([eE] [+-]? digit+)? <Number>
136
+ end
137
+
138
+ rule digit
139
+ [0-9]
140
+ end
141
+
142
+ rule boolean
143
+ (true / false) <Boolean>
144
+ end
145
+
146
+ rule true
147
+ "true" <True>
148
+ end
149
+
150
+ rule false
151
+ "false" <False>
152
+ end
153
+
154
+ rule null
155
+ "null" <Null>
156
+ end
157
+
158
+ rule space
159
+ " "*
160
+ end
161
+ end
162
+
@@ -0,0 +1,260 @@
1
+ module JsonQuery
2
+
3
+ class Query < Treetop::Runtime::SyntaxNode
4
+ def value(root, symbols, current = nil)
5
+ object = identifier.value(root, symbols, current)
6
+ filters.inject(object) { |value, filter| filter.value(value, root, symbols, current) }
7
+ end
8
+
9
+ def filters
10
+ elements[1].elements
11
+ end
12
+ end
13
+
14
+ module Identifier
15
+ end
16
+
17
+ class Root < Treetop::Runtime::SyntaxNode
18
+ def value(root, symbols, current = nil)
19
+ root
20
+ end
21
+ end
22
+
23
+ class Current < Treetop::Runtime::SyntaxNode
24
+ def value(root, symbols, current = nil)
25
+ current
26
+ end
27
+ end
28
+
29
+ class Symbol < Treetop::Runtime::SyntaxNode
30
+ def value(root, symbols, current = nil)
31
+ symbols[text_value] || FieldAccess.access(current, text_value)
32
+ end
33
+ end
34
+
35
+ module Filter
36
+ end
37
+
38
+ module FieldAccess
39
+ def index(object, root, symbols, current = nil)
40
+ element = elements[1]
41
+ return [element.text_value] if Symbol === element
42
+ element.value(root, symbols, object)
43
+ end
44
+
45
+ def value(object, root, symbols, current = nil)
46
+ indexes = index(object, root, symbols, current)
47
+ indexes.size == 1 ?
48
+ FieldAccess.access(object, indexes.first) :
49
+ indexes.map { |i| FieldAccess.access(object, i) }
50
+ end
51
+
52
+ def self.access(object, index)
53
+ return (Hash === object ? object.values : object) if index == :*
54
+ return object[index] if Array === object and Numeric === index
55
+
56
+ if Hash === object
57
+ key = [index, index.to_s, index.to_sym].find { |i| object.has_key?(i) }
58
+ return object[key] if key
59
+ end
60
+
61
+ return object.__send__(index) if object.respond_to?(index)
62
+ object.instance_variable_get("@#{ index }")
63
+ end
64
+ end
65
+
66
+ class FieldAccessExpression < Treetop::Runtime::SyntaxNode
67
+ def value(root, symbols, current = nil)
68
+ exprs = [first] + others.elements.map { |e| e.expression }
69
+ exprs.map { |e| e.value(root, symbols, current) }
70
+ end
71
+ end
72
+
73
+ class AllFilter < Treetop::Runtime::SyntaxNode
74
+ def value(root, symbols, current = nil)
75
+ [:*]
76
+ end
77
+ end
78
+
79
+ class BooleanFilter < Treetop::Runtime::SyntaxNode
80
+ def value(list, root, symbols, current = nil)
81
+ list.select do |object|
82
+ boolean_expression.value(root, symbols, object)
83
+ end
84
+ end
85
+ end
86
+
87
+ class MapFilter < Treetop::Runtime::SyntaxNode
88
+ def value(list, root, symbols, current = nil)
89
+ list.map do |object|
90
+ expression.value(root, symbols, object)
91
+ end
92
+ end
93
+ end
94
+
95
+ class SortFilter < Treetop::Runtime::SyntaxNode
96
+ def value(list, root, symbols, current = nil)
97
+ result = list.sort_by { |object| expression.value(root, symbols, object) }
98
+ result.reverse! if sorter.text_value == "\\"
99
+ result
100
+ end
101
+ end
102
+
103
+ class Sorter < Treetop::Runtime::SyntaxNode
104
+ end
105
+
106
+ class And < Treetop::Runtime::SyntaxNode
107
+ def value(root, symbols, current = nil)
108
+ first.value(root, symbols, current) && second.value(root, symbols, current)
109
+ end
110
+ end
111
+
112
+ class Or < Treetop::Runtime::SyntaxNode
113
+ def value(root, symbols, current = nil)
114
+ first.value(root, symbols, current) || second.value(root, symbols, current)
115
+ end
116
+ end
117
+
118
+ class BooleanAtom < Treetop::Runtime::SyntaxNode
119
+ def value(root, symbols, current = nil)
120
+ element = elements[1]
121
+ return element.boolean_expression.value(root, symbols, current) if element.respond_to?(:boolean_expression)
122
+ comparator.value(first.value(root, symbols, current), second.value(root, symbols, current))
123
+ end
124
+
125
+ def comparator
126
+ elements[1].comparator
127
+ end
128
+
129
+ def first
130
+ elements[1].first
131
+ end
132
+
133
+ def second
134
+ elements[1].second
135
+ end
136
+ end
137
+
138
+ class Multiplicative < Treetop::Runtime::SyntaxNode
139
+ def value(root, symbols, current = nil)
140
+ operator.value(first.value(root, symbols, current), second.value(root, symbols, current))
141
+ end
142
+ end
143
+
144
+ class Additive < Treetop::Runtime::SyntaxNode
145
+ def value(root, symbols, current = nil)
146
+ operator.value(first.value(root, symbols, current), second.value(root, symbols, current))
147
+ end
148
+ end
149
+
150
+ class Atom < Treetop::Runtime::SyntaxNode
151
+ def value(root, symbols, current = nil)
152
+ element = elements[1]
153
+ return element.expression.value(root, symbols, current) if element.respond_to?(:expression)
154
+ element.value(root, symbols, current)
155
+ end
156
+ end
157
+
158
+ class Multiplication < Treetop::Runtime::SyntaxNode
159
+ def value(expr1, expr2)
160
+ expr1 * expr2
161
+ end
162
+ end
163
+
164
+ class Division < Treetop::Runtime::SyntaxNode
165
+ def value(expr1, expr2)
166
+ expr1 / expr2
167
+ end
168
+ end
169
+
170
+ class Addition < Treetop::Runtime::SyntaxNode
171
+ def value(expr1, expr2)
172
+ String === expr1 || String === expr2 ?
173
+ expr1.to_s + expr2.to_s :
174
+ expr1 + expr2
175
+ end
176
+ end
177
+
178
+ class Subtraction < Treetop::Runtime::SyntaxNode
179
+ def value(expr1, expr2)
180
+ expr1 - expr2
181
+ end
182
+ end
183
+
184
+ module Comparator
185
+ end
186
+
187
+ class Equal < Treetop::Runtime::SyntaxNode
188
+ def value(expr1, expr2)
189
+ expr1 == expr2
190
+ end
191
+ end
192
+
193
+ class NotEqual < Treetop::Runtime::SyntaxNode
194
+ def value(expr1, expr2)
195
+ expr1 != expr2
196
+ end
197
+ end
198
+
199
+ class LessThan < Treetop::Runtime::SyntaxNode
200
+ def value(expr1, expr2)
201
+ expr1 < expr2
202
+ end
203
+ end
204
+
205
+ class LessThanOrEqual < Treetop::Runtime::SyntaxNode
206
+ def value(expr1, expr2)
207
+ expr1 <= expr2
208
+ end
209
+ end
210
+
211
+ class GreaterThan < Treetop::Runtime::SyntaxNode
212
+ def value(expr1, expr2)
213
+ expr1 > expr2
214
+ end
215
+ end
216
+
217
+ class GreaterThanOrEqual < Treetop::Runtime::SyntaxNode
218
+ def value(expr1, expr2)
219
+ expr1 >= expr2
220
+ end
221
+ end
222
+
223
+ class String < Treetop::Runtime::SyntaxNode
224
+ def value(root, symbols, current = nil)
225
+ @value ||= eval(text_value)
226
+ end
227
+ end
228
+
229
+ class Number < Treetop::Runtime::SyntaxNode
230
+ def value(root, symbols, current = nil)
231
+ @value ||= eval(text_value)
232
+ end
233
+ end
234
+
235
+ module Boolean
236
+ def value(root, symbols, current = nil)
237
+ data.value
238
+ end
239
+ end
240
+
241
+ class True < Treetop::Runtime::SyntaxNode
242
+ def value(root, symbols, current = nil)
243
+ true
244
+ end
245
+ end
246
+
247
+ class False < Treetop::Runtime::SyntaxNode
248
+ def value(root, symbols, current = nil)
249
+ false
250
+ end
251
+ end
252
+
253
+ class Null < Treetop::Runtime::SyntaxNode
254
+ def value(root, symbols, current = nil)
255
+ nil
256
+ end
257
+ end
258
+
259
+ end
260
+
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'treetop'
3
+
4
+ %w(walker parser node reference observer).each do |path|
5
+ require File.dirname(__FILE__) + '/siren/' + path
6
+ end
7
+ %w(json json_query json_query/nodes).each do |path|
8
+ require File.dirname(__FILE__) + '/' + path
9
+ end
10
+
11
+ $p = JsonQueryParser.new
12
+
13
+ class JsonParser
14
+ include Siren::Walker
15
+ end
16
+
17
+ module Siren
18
+ TYPE_FIELD = "type"
19
+ ID_FIELD = "id"
20
+ REF_FIELD = "$ref"
21
+
22
+ def self.parse(string, &block)
23
+ @json_parser ||= JsonParser.new
24
+ Reference.flush!
25
+ @symbols = {}
26
+
27
+ result = @json_parser.parse(string).value rescue nil
28
+
29
+ @json_parser.walk(result) do |holder, key, value|
30
+ if Hash === value && value[REF_FIELD]
31
+ value = Reference.new(value) do |ref, root, symbols|
32
+ holder[key] = ref.find(root, symbols, holder)
33
+ end
34
+ end
35
+ value
36
+ end
37
+
38
+ @json_parser.walk(result) do |holder, key, value|
39
+ if Hash === value
40
+ id = value[ID_FIELD]
41
+ value = Node.from_json(value)
42
+ @symbols[id] = value
43
+ end
44
+ value
45
+ end
46
+
47
+ Reference.resolve!(result, @symbols)
48
+ @json_parser.walk(result, &block) if block_given?
49
+
50
+ result
51
+ end
52
+
53
+ def self.query(expression, root)
54
+ compile_query(expression).value(root, @symbols ||{})
55
+ end
56
+
57
+ def self.compile_query(expression)
58
+ @query_parser ||= JsonQueryParser.new
59
+ @query_cache ||= {}
60
+ @query_cache[expression] ||= @query_parser.parse(expression)
61
+ end
62
+ end
63
+