siren 0.2.0
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.
- data/History.txt +16 -0
- data/Manifest.txt +22 -0
- data/README.txt +318 -0
- data/Rakefile +19 -0
- data/lib/siren.rb +76 -0
- data/lib/siren/json.rb +1039 -0
- data/lib/siren/json.tt +86 -0
- data/lib/siren/json_query.rb +2414 -0
- data/lib/siren/json_query.tt +184 -0
- data/lib/siren/json_query_nodes.rb +333 -0
- data/lib/siren/node.rb +37 -0
- data/lib/siren/parser.rb +205 -0
- data/lib/siren/reference.rb +30 -0
- data/lib/siren/walker.rb +33 -0
- data/test/fixtures/beatles.json +11 -0
- data/test/fixtures/car.rb +14 -0
- data/test/fixtures/names.json +7 -0
- data/test/fixtures/people.json +34 -0
- data/test/fixtures/person.rb +15 -0
- data/test/fixtures/refs.json +26 -0
- data/test/fixtures/store.json +32 -0
- data/test/test_siren.rb +181 -0
- metadata +109 -0
@@ -0,0 +1,184 @@
|
|
1
|
+
module Siren
|
2
|
+
grammar JsonQuery
|
3
|
+
rule expression
|
4
|
+
sum / product / divmod / atom
|
5
|
+
end
|
6
|
+
|
7
|
+
rule boolean_expression
|
8
|
+
or_expression / and_expression / comparison / boolean_atom
|
9
|
+
end
|
10
|
+
|
11
|
+
rule or_expression
|
12
|
+
first:and_expression "|" second:or_expression <Or> / and_expression
|
13
|
+
end
|
14
|
+
|
15
|
+
rule and_expression
|
16
|
+
first:comparison "&" second:and_expression <And> / comparison
|
17
|
+
end
|
18
|
+
|
19
|
+
rule comparison
|
20
|
+
first:expression comparator second:expression <Comparison> / boolean_atom
|
21
|
+
end
|
22
|
+
|
23
|
+
rule boolean_atom
|
24
|
+
space ("(" boolean_expression ")" / boolean) space <BooleanAtom>
|
25
|
+
end
|
26
|
+
|
27
|
+
rule sum
|
28
|
+
first:product operator:(add / subtract) second:sum <Sum> / product
|
29
|
+
end
|
30
|
+
|
31
|
+
rule product
|
32
|
+
first:divmod operator:(times / divide) second:product <Product> / divmod
|
33
|
+
end
|
34
|
+
|
35
|
+
rule divmod
|
36
|
+
first:atom '%' second:divmod <Divmod> / atom
|
37
|
+
end
|
38
|
+
|
39
|
+
rule atom
|
40
|
+
space ("(" expression ")" / query / number / string / boolean / null) space <Atom>
|
41
|
+
end
|
42
|
+
|
43
|
+
rule times
|
44
|
+
"*" <Multiplication>
|
45
|
+
end
|
46
|
+
|
47
|
+
rule divide
|
48
|
+
"/" <Division>
|
49
|
+
end
|
50
|
+
|
51
|
+
rule add
|
52
|
+
"+" <Addition>
|
53
|
+
end
|
54
|
+
|
55
|
+
rule subtract
|
56
|
+
"-" <Subtraction>
|
57
|
+
end
|
58
|
+
|
59
|
+
rule comparator
|
60
|
+
(not_equal / lte / gte / equal / match / lt / gt) <Comparator>
|
61
|
+
end
|
62
|
+
|
63
|
+
rule equal
|
64
|
+
"=" <Equal>
|
65
|
+
end
|
66
|
+
|
67
|
+
rule match
|
68
|
+
"~" <Match>
|
69
|
+
end
|
70
|
+
|
71
|
+
rule not_equal
|
72
|
+
"!=" <NotEqual>
|
73
|
+
end
|
74
|
+
|
75
|
+
rule lt
|
76
|
+
"<" <LessThan>
|
77
|
+
end
|
78
|
+
|
79
|
+
rule lte
|
80
|
+
"<=" <LessThanOrEqual>
|
81
|
+
end
|
82
|
+
|
83
|
+
rule gt
|
84
|
+
">" <GreaterThan>
|
85
|
+
end
|
86
|
+
|
87
|
+
rule gte
|
88
|
+
">=" <GreaterThanOrEqual>
|
89
|
+
end
|
90
|
+
|
91
|
+
rule string
|
92
|
+
"'" ('\\' ("'" / '\\' / '/' / 'b' / 'f' / 'n' / 'r' / 't' / 'u' hex hex hex hex) / [^\'\\])* "'" <String>
|
93
|
+
end
|
94
|
+
|
95
|
+
rule number
|
96
|
+
"-"? ("0" / [1-9] digit*) ("." digit+)? ([eE] [+-]? digit+)? <Number>
|
97
|
+
end
|
98
|
+
|
99
|
+
rule digit
|
100
|
+
[0-9]
|
101
|
+
end
|
102
|
+
|
103
|
+
rule boolean
|
104
|
+
(true / false) <Boolean>
|
105
|
+
end
|
106
|
+
|
107
|
+
rule true
|
108
|
+
"true" <True>
|
109
|
+
end
|
110
|
+
|
111
|
+
rule false
|
112
|
+
"false" <False>
|
113
|
+
end
|
114
|
+
|
115
|
+
rule null
|
116
|
+
"null" <Null>
|
117
|
+
end
|
118
|
+
|
119
|
+
rule space
|
120
|
+
" "*
|
121
|
+
end
|
122
|
+
|
123
|
+
rule query
|
124
|
+
identifier filter* <Query>
|
125
|
+
end
|
126
|
+
|
127
|
+
rule identifier
|
128
|
+
(root / current / symbol) <Identifier>
|
129
|
+
end
|
130
|
+
|
131
|
+
rule root
|
132
|
+
"$" <Root>
|
133
|
+
end
|
134
|
+
|
135
|
+
rule current
|
136
|
+
"@" <Current>
|
137
|
+
end
|
138
|
+
|
139
|
+
rule symbol
|
140
|
+
[A-Za-z$_] [A-Za-z0-9$_]* <Symbol>
|
141
|
+
end
|
142
|
+
|
143
|
+
rule filter
|
144
|
+
(slice_access / recursive_access / field_access / boolean_filter / map_filter / sort_filter) <Filter>
|
145
|
+
end
|
146
|
+
|
147
|
+
rule slice_access
|
148
|
+
"[" head:number ":" tail:number step:(":" number)? "]" <SliceAccess>
|
149
|
+
end
|
150
|
+
|
151
|
+
rule recursive_access
|
152
|
+
".." symbol <RecursiveAccess>
|
153
|
+
end
|
154
|
+
|
155
|
+
rule field_access
|
156
|
+
("." (symbol / all) / "[" (field_access_expression / all) "]") <FieldAccess>
|
157
|
+
end
|
158
|
+
|
159
|
+
rule field_access_expression
|
160
|
+
first:expression others:("," expression)* <FieldAccessExpression>
|
161
|
+
end
|
162
|
+
|
163
|
+
rule all
|
164
|
+
"*" <AllFilter>
|
165
|
+
end
|
166
|
+
|
167
|
+
rule boolean_filter
|
168
|
+
recursive:".."? "[?" boolean_expression "]" <BooleanFilter>
|
169
|
+
end
|
170
|
+
|
171
|
+
rule map_filter
|
172
|
+
"[=" expression "]" <MapFilter>
|
173
|
+
end
|
174
|
+
|
175
|
+
rule sort_filter
|
176
|
+
"[" first:(sorter expression) others:("," sorter expression)* "]" <SortFilter>
|
177
|
+
end
|
178
|
+
|
179
|
+
rule sorter
|
180
|
+
space ("/" / "\\") space <Sorter>
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
@@ -0,0 +1,333 @@
|
|
1
|
+
module Siren
|
2
|
+
module JsonQuery
|
3
|
+
|
4
|
+
module Query
|
5
|
+
def value(root, symbols, current = nil)
|
6
|
+
object = identifier.value(root, symbols, current)
|
7
|
+
filters.inject(object) { |value, filter| filter.value(value, root, symbols, current) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def filters
|
11
|
+
elements[1].elements
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Identifier
|
16
|
+
end
|
17
|
+
|
18
|
+
module Root
|
19
|
+
def value(root, symbols, current = nil)
|
20
|
+
root
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Current
|
25
|
+
def value(root, symbols, current = nil)
|
26
|
+
current
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Symbol
|
31
|
+
def value(root, symbols, current = nil)
|
32
|
+
symbols[text_value] || FieldAccess.access(current, text_value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Filter
|
37
|
+
end
|
38
|
+
|
39
|
+
module SliceAccess
|
40
|
+
def value(object, root, symbols, current = nil)
|
41
|
+
a, b = *[head, tail].map { |x| x.value(root, symbols, current) }
|
42
|
+
s = step.respond_to?(:number) ? step.number.value(root, symbols, current) : 1
|
43
|
+
result = []
|
44
|
+
while a <= b
|
45
|
+
result << object[a]
|
46
|
+
a += s
|
47
|
+
end
|
48
|
+
result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module RecursiveAccess
|
53
|
+
def value(object, root, symbols, current = nil)
|
54
|
+
name = elements[1].text_value
|
55
|
+
results, visited = [], Set.new
|
56
|
+
|
57
|
+
visitor = lambda do |visitee|
|
58
|
+
return unless visited.add?(visitee)
|
59
|
+
Siren.each(visitee) do |index, value|
|
60
|
+
results << value if index == name
|
61
|
+
visitor.call(value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
visitor.call(object)
|
66
|
+
results
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module FieldAccess
|
71
|
+
def index(object, root, symbols, current = nil)
|
72
|
+
element = elements[1]
|
73
|
+
return [element.text_value] if Symbol === element
|
74
|
+
element.value(root, symbols, object)
|
75
|
+
end
|
76
|
+
|
77
|
+
def value(object, root, symbols, current = nil)
|
78
|
+
indexes = index(object, root, symbols, current)
|
79
|
+
indexes.size == 1 ?
|
80
|
+
FieldAccess.access(object, indexes.first) :
|
81
|
+
indexes.map { |i| FieldAccess.access(object, i) }
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.access(object, index)
|
85
|
+
return (Hash === object ? object.values : object) if index == :*
|
86
|
+
return object[index] if Array === object and Numeric === index
|
87
|
+
|
88
|
+
if Hash === object
|
89
|
+
key = [index, index.to_s, index.to_sym].find { |i| object.has_key?(i) }
|
90
|
+
return object[key] if key
|
91
|
+
end
|
92
|
+
|
93
|
+
return object.__send__(index) if object.respond_to?(index)
|
94
|
+
object.instance_variable_get("@#{ index }")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
module FieldAccessExpression
|
99
|
+
def value(root, symbols, current = nil)
|
100
|
+
exprs = [first] + others.elements.map { |e| e.expression }
|
101
|
+
exprs.map { |e| e.value(root, symbols, current) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
module AllFilter
|
106
|
+
def value(root, symbols, current = nil)
|
107
|
+
[:*]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
module BooleanFilter
|
112
|
+
def value(list, root, symbols, current = nil)
|
113
|
+
results, visited = [], Set.new
|
114
|
+
|
115
|
+
visitor = lambda do |visitee|
|
116
|
+
return unless visited.add?(visitee)
|
117
|
+
Siren.each(visitee) do |index, value|
|
118
|
+
begin
|
119
|
+
results << value if boolean_expression.value(root, symbols, value)
|
120
|
+
rescue
|
121
|
+
end
|
122
|
+
visitor.call(value) if recursive.text_value == '..'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
visitor.call(list)
|
127
|
+
results
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
module MapFilter
|
132
|
+
def value(list, root, symbols, current = nil)
|
133
|
+
list.map do |object|
|
134
|
+
expression.value(root, symbols, object)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
module SortFilter
|
140
|
+
def value(list, root, symbols, current = nil)
|
141
|
+
sorters = [[first.expression, first.sorter]] +
|
142
|
+
others.elements.map { |e| [e.expression, e.sorter] }
|
143
|
+
|
144
|
+
list.sort do |a, b|
|
145
|
+
sorters.inject(0) do |outcome, sorter|
|
146
|
+
if outcome.nonzero?
|
147
|
+
outcome
|
148
|
+
else
|
149
|
+
f, g = sorter[0].value(root, symbols, a), sorter[0].value(root, symbols, b)
|
150
|
+
sorter[1].value * (f <=> g)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
module Sorter
|
158
|
+
ORDERS = {"/" => 1, "\\" => -1}
|
159
|
+
|
160
|
+
def value
|
161
|
+
ORDERS[elements[1].text_value]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
module And
|
166
|
+
def value(root, symbols, current = nil)
|
167
|
+
first.value(root, symbols, current) && second.value(root, symbols, current)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
module Or
|
172
|
+
def value(root, symbols, current = nil)
|
173
|
+
first.value(root, symbols, current) || second.value(root, symbols, current)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
module Comparison
|
178
|
+
def value(root, symbols, current = nil)
|
179
|
+
comparator.value(first.value(root, symbols, current), second.value(root, symbols, current))
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
module BooleanAtom
|
184
|
+
def value(root, symbols, current = nil)
|
185
|
+
element = elements[1]
|
186
|
+
return element.boolean_expression.value(root, symbols, current) if element.respond_to?(:boolean_expression)
|
187
|
+
element.value(root, symbols, current)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
module Divmod
|
192
|
+
def value(root, symbols, current = nil)
|
193
|
+
first.value(root, symbols, current) % second.value(root, symbols, current)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
module Product
|
198
|
+
def value(root, symbols, current = nil)
|
199
|
+
operator.value(first.value(root, symbols, current), second.value(root, symbols, current))
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
module Sum
|
204
|
+
def value(root, symbols, current = nil)
|
205
|
+
operator.value(first.value(root, symbols, current), second.value(root, symbols, current))
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
module Atom
|
210
|
+
def value(root, symbols, current = nil)
|
211
|
+
element = elements[1]
|
212
|
+
return element.expression.value(root, symbols, current) if element.respond_to?(:expression)
|
213
|
+
element.value(root, symbols, current)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
module Multiplication
|
218
|
+
def value(expr1, expr2)
|
219
|
+
expr1 * expr2
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
module Division
|
224
|
+
def value(expr1, expr2)
|
225
|
+
expr1 / expr2
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
module Addition
|
230
|
+
def value(expr1, expr2)
|
231
|
+
String === expr1 || String === expr2 ?
|
232
|
+
expr1.to_s + expr2.to_s :
|
233
|
+
expr1 + expr2
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
module Subtraction
|
238
|
+
def value(expr1, expr2)
|
239
|
+
expr1 - expr2
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
module Comparator
|
244
|
+
end
|
245
|
+
|
246
|
+
module Equal
|
247
|
+
def value(expr1, expr2)
|
248
|
+
return expr1 == expr2 unless expr2.respond_to?(:gsub)
|
249
|
+
expr1 =~ %r{^#{Match.convert(expr2)}$}
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
module Match
|
254
|
+
def value(expr1, expr2)
|
255
|
+
return expr1 == expr2 unless expr2.respond_to?(:gsub)
|
256
|
+
expr1 =~ %r{^#{Match.convert(expr2)}$}i
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.convert(string)
|
260
|
+
string.gsub(/([\.\+\[\]\{\}\(\)\^\$])/) { "\\#{$1}" }.
|
261
|
+
gsub('*', '.*').gsub('?', '.')
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
module NotEqual
|
266
|
+
def value(expr1, expr2)
|
267
|
+
expr1 != expr2
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
module LessThan
|
272
|
+
def value(expr1, expr2)
|
273
|
+
expr1 < expr2
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
module LessThanOrEqual
|
278
|
+
def value(expr1, expr2)
|
279
|
+
expr1 <= expr2
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
module GreaterThan
|
284
|
+
def value(expr1, expr2)
|
285
|
+
expr1 > expr2
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
module GreaterThanOrEqual
|
290
|
+
def value(expr1, expr2)
|
291
|
+
expr1 >= expr2
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
module String
|
296
|
+
def value(root, symbols, current = nil)
|
297
|
+
@value ||= eval(text_value)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
module Number
|
302
|
+
def value(root, symbols, current = nil)
|
303
|
+
@value ||= eval(text_value)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
module Boolean
|
308
|
+
def value(root, symbols, current = nil)
|
309
|
+
data.value
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
module True
|
314
|
+
def value(root, symbols, current = nil)
|
315
|
+
true
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
module False
|
320
|
+
def value(root, symbols, current = nil)
|
321
|
+
false
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
module Null
|
326
|
+
def value(root, symbols, current = nil)
|
327
|
+
nil
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|