json_select 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +18 -0
- data/json_select.gemspec +23 -0
- data/lib/json_select.rb +35 -0
- data/lib/json_select/ast/combination_selector.rb +14 -0
- data/lib/json_select/ast/complex_expr.rb +27 -0
- data/lib/json_select/ast/even_expr.rb +7 -0
- data/lib/json_select/ast/hash_selector.rb +12 -0
- data/lib/json_select/ast/odd_expr.rb +7 -0
- data/lib/json_select/ast/pseudo_selector.rb +24 -0
- data/lib/json_select/ast/selector_group.rb +17 -0
- data/lib/json_select/ast/simple_expr.rb +7 -0
- data/lib/json_select/ast/simple_selector.rb +23 -0
- data/lib/json_select/ast/type_selector.rb +8 -0
- data/lib/json_select/ast/universal_selector.rb +7 -0
- data/lib/json_select/parser.rb +19 -0
- data/lib/json_select/selector.rb +176 -0
- data/lib/json_select/selector_parser.rb +1251 -0
- data/lib/json_select/selector_parser.tt +161 -0
- data/lib/json_select/version.rb +3 -0
- data/spec/conformance_spec.rb +41 -0
- data/spec/fixtures/README.md +14 -0
- data/spec/fixtures/alltests.txt +31 -0
- data/spec/fixtures/basic.json +31 -0
- data/spec/fixtures/basic.xml +31 -0
- data/spec/fixtures/basic_first-child.ast +6 -0
- data/spec/fixtures/basic_first-child.output +6 -0
- data/spec/fixtures/basic_first-child.selector +2 -0
- data/spec/fixtures/basic_grouping.ast +12 -0
- data/spec/fixtures/basic_grouping.output +4 -0
- data/spec/fixtures/basic_grouping.selector +1 -0
- data/spec/fixtures/basic_id.ast +3 -0
- data/spec/fixtures/basic_id.output +1 -0
- data/spec/fixtures/basic_id.selector +1 -0
- data/spec/fixtures/basic_id_multiple.ast +3 -0
- data/spec/fixtures/basic_id_multiple.output +3 -0
- data/spec/fixtures/basic_id_multiple.selector +1 -0
- data/spec/fixtures/basic_id_quotes.ast +3 -0
- data/spec/fixtures/basic_id_quotes.output +2 -0
- data/spec/fixtures/basic_id_quotes.selector +1 -0
- data/spec/fixtures/basic_id_with_type.ast +4 -0
- data/spec/fixtures/basic_id_with_type.output +1 -0
- data/spec/fixtures/basic_id_with_type.selector +1 -0
- data/spec/fixtures/basic_last-child.ast +6 -0
- data/spec/fixtures/basic_last-child.output +6 -0
- data/spec/fixtures/basic_last-child.selector +2 -0
- data/spec/fixtures/basic_nth-child-2.ast +6 -0
- data/spec/fixtures/basic_nth-child-2.output +13 -0
- data/spec/fixtures/basic_nth-child-2.selector +1 -0
- data/spec/fixtures/basic_nth-child.ast +6 -0
- data/spec/fixtures/basic_nth-child.output +7 -0
- data/spec/fixtures/basic_nth-child.selector +1 -0
- data/spec/fixtures/basic_nth-last-child.ast +6 -0
- data/spec/fixtures/basic_nth-last-child.output +6 -0
- data/spec/fixtures/basic_nth-last-child.selector +1 -0
- data/spec/fixtures/basic_root_pseudo.ast +3 -0
- data/spec/fixtures/basic_root_pseudo.output +31 -0
- data/spec/fixtures/basic_root_pseudo.selector +1 -0
- data/spec/fixtures/basic_type.ast +3 -0
- data/spec/fixtures/basic_type.output +14 -0
- data/spec/fixtures/basic_type.selector +1 -0
- data/spec/fixtures/basic_type2.ast +3 -0
- data/spec/fixtures/basic_type2.output +1 -0
- data/spec/fixtures/basic_type2.selector +1 -0
- data/spec/fixtures/basic_type3.ast +3 -0
- data/spec/fixtures/basic_type3.output +47 -0
- data/spec/fixtures/basic_type3.selector +1 -0
- data/spec/fixtures/basic_universal.ast +2 -0
- data/spec/fixtures/basic_universal.output +85 -0
- data/spec/fixtures/basic_universal.selector +1 -0
- data/spec/spec_helper.rb +6 -0
- metadata +190 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
module JSONSelect
|
2
|
+
grammar SelectorParser
|
3
|
+
|
4
|
+
# selectors_group
|
5
|
+
# : selector [ `,` selector ]*
|
6
|
+
# ;
|
7
|
+
rule selectors_group
|
8
|
+
a:selector b:( ',' c:selector )* <JSONSelect::Ast::SelectorGroup>
|
9
|
+
end
|
10
|
+
|
11
|
+
# selector
|
12
|
+
# : simple_selector_sequence [ combinator simple_selector_sequence ]*
|
13
|
+
# ;
|
14
|
+
rule selector
|
15
|
+
a:simple_selector_sequence b:( c:combinator d:simple_selector_sequence )* <JSONSelect::Ast::CombinationSelector>
|
16
|
+
end
|
17
|
+
|
18
|
+
# combinator
|
19
|
+
# : `>` | \s+
|
20
|
+
# ;
|
21
|
+
rule combinator
|
22
|
+
'>' / [\s]+
|
23
|
+
end
|
24
|
+
|
25
|
+
# simple_selector_sequence
|
26
|
+
# /* why allow multiple HASH entities in the grammar? */
|
27
|
+
# : [ type_selector | universal ]
|
28
|
+
# [ hash | pseudo ]*
|
29
|
+
# | [ hash | pseudo ]+
|
30
|
+
# ;
|
31
|
+
rule simple_selector_sequence
|
32
|
+
( a:( type_selector / universal ) b:( hash / pseudo )* <JSONSelect::Ast::SimpleSelector> )
|
33
|
+
/
|
34
|
+
( ( hash / pseudo )+ <JSONSelect::Ast::SimpleSelector> )
|
35
|
+
end
|
36
|
+
|
37
|
+
# type_selector
|
38
|
+
# : `object` | `array` | `number` | `string` | `boolean` | `null`
|
39
|
+
# ;
|
40
|
+
rule type_selector
|
41
|
+
('object' / 'array' / 'number' / 'string' / 'boolean' / 'null') <JSONSelect::Ast::TypeSelector>
|
42
|
+
end
|
43
|
+
|
44
|
+
# universal
|
45
|
+
# : '*'
|
46
|
+
# ;
|
47
|
+
rule universal
|
48
|
+
'*' <JSONSelect::Ast::UniversalSelector>
|
49
|
+
end
|
50
|
+
|
51
|
+
# hash
|
52
|
+
# : `.` name
|
53
|
+
# | `.` json_string
|
54
|
+
# ;
|
55
|
+
rule hash
|
56
|
+
( ( '.' name ) / ( '.' json_string ) ) <JSONSelect::Ast::HashSelector>
|
57
|
+
end
|
58
|
+
|
59
|
+
# pseudo
|
60
|
+
# /* Note that pseudo-elements are restricted to one per selector and */
|
61
|
+
# /* occur only in the last simple_selector_sequence. */
|
62
|
+
# : `:` pseudo_class_name
|
63
|
+
# | `:` pseudo_function_name `(` expression `)`
|
64
|
+
# ;
|
65
|
+
rule pseudo
|
66
|
+
( ':' a:pseudo_class_name <JSONSelect::Ast::PseudoSelector> ) /
|
67
|
+
( ':' a:pseudo_function_name '(' e:expression ')' <JSONSelect::Ast::PseudoSelector> )
|
68
|
+
end
|
69
|
+
|
70
|
+
# pseudo_class_name
|
71
|
+
# : `root` | `first-child` | `last-child` | `only-child`
|
72
|
+
rule pseudo_class_name
|
73
|
+
'root' / 'first-child' / 'last-child' / 'only-child'
|
74
|
+
end
|
75
|
+
|
76
|
+
# pseudo_function_name
|
77
|
+
# : `nth-child` | `nth-last-child`
|
78
|
+
rule pseudo_function_name
|
79
|
+
'nth-child' / 'nth-last-child'
|
80
|
+
end
|
81
|
+
|
82
|
+
# expression
|
83
|
+
# /* expression is and of the form "an+b" */
|
84
|
+
# : TODO
|
85
|
+
# ;
|
86
|
+
# /^ \(
|
87
|
+
# (?: ([+-]?) ([0-9]*) n (?:([+-]) ([0-9]) )?
|
88
|
+
# | (odd|even)
|
89
|
+
# | ( [+-]? [0-9]+ )
|
90
|
+
# )
|
91
|
+
# \) /;
|
92
|
+
rule expression
|
93
|
+
('odd' <JSONSelect::Ast::OddExpr> ) /
|
94
|
+
('even' <JSONSelect::Ast::EvenExpr>) /
|
95
|
+
( a:[+-]? b:[0-9]* 'n' c:( [+-] [0-9] )? <JSONSelect::Ast::ComplexExpr> ) /
|
96
|
+
( [+-]? [0-9]+ <JSONSelect::Ast::SimpleExpr> )
|
97
|
+
end
|
98
|
+
|
99
|
+
# json_string
|
100
|
+
# : `"` json_chars* `"`
|
101
|
+
# ;
|
102
|
+
rule json_string
|
103
|
+
["] json_chars* ["]
|
104
|
+
end
|
105
|
+
|
106
|
+
# json_chars
|
107
|
+
# : any-Unicode-character-except-"-or-\-or-control-character
|
108
|
+
# | `\"`
|
109
|
+
# | `\\`
|
110
|
+
# | `\/`
|
111
|
+
# | `\b`
|
112
|
+
# | `\f`
|
113
|
+
# | `\n`
|
114
|
+
# | `\r`
|
115
|
+
# | `\t`
|
116
|
+
# | \u four-hex-digits
|
117
|
+
# ;
|
118
|
+
rule json_chars
|
119
|
+
[^\\"] /
|
120
|
+
( [\\] ["\\/bfnrt] )
|
121
|
+
end
|
122
|
+
|
123
|
+
# name
|
124
|
+
# : nmstart nmchar*
|
125
|
+
# ;
|
126
|
+
rule name
|
127
|
+
nmstart nmchar*
|
128
|
+
end
|
129
|
+
|
130
|
+
# nmstart
|
131
|
+
# : escape | [_a-zA-Z] | nonascii
|
132
|
+
# ;
|
133
|
+
rule nmstart
|
134
|
+
escape / [_a-zA-Z] / nonascii
|
135
|
+
end
|
136
|
+
|
137
|
+
# nmchar
|
138
|
+
# : [_a-zA-Z0-9-]
|
139
|
+
# | escape
|
140
|
+
# | nonascii
|
141
|
+
# ;
|
142
|
+
rule nmchar
|
143
|
+
[_a-zA-Z0-9-] / escape / nonascii
|
144
|
+
end
|
145
|
+
|
146
|
+
# escape
|
147
|
+
# : \\[^\r\n\f0-9a-fA-F]
|
148
|
+
# ;
|
149
|
+
rule escape
|
150
|
+
[\\] [^\r\n\f0-9a-fA-F]
|
151
|
+
end
|
152
|
+
|
153
|
+
# nonascii
|
154
|
+
# : [^\0-0177]
|
155
|
+
# ;
|
156
|
+
rule nonascii
|
157
|
+
[^\0-0177]
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
describe "JSONSelect", "conformance" do
|
2
|
+
|
3
|
+
%w( basic ).each do |test|
|
4
|
+
selectors = "../fixtures/#{test}_*.selector"
|
5
|
+
selectors = Dir[File.expand_path(selectors, __FILE__)]
|
6
|
+
|
7
|
+
describe "(#{test})" do
|
8
|
+
|
9
|
+
let(:input) do
|
10
|
+
path = File.expand_path("../fixtures/#{test}.json", __FILE__)
|
11
|
+
Yajl::Parser.parse(File.read(path))
|
12
|
+
end
|
13
|
+
|
14
|
+
selectors.each do |selector|
|
15
|
+
basename = File.basename(selector, '.selector')
|
16
|
+
name = basename[(test.size + 1)..-1]
|
17
|
+
output = File.expand_path("../fixtures/#{basename}.output", __FILE__)
|
18
|
+
ast = File.expand_path("../fixtures/#{basename}.ast", __FILE__)
|
19
|
+
|
20
|
+
describe "(#{name})" do
|
21
|
+
|
22
|
+
it "parses the selector" do
|
23
|
+
ast = Yajl::Parser.parse(File.read(ast))
|
24
|
+
s = JSONSelect(File.read(selector).strip)
|
25
|
+
s.should be_a(JSONSelect::Selector)
|
26
|
+
s.ast.should == ast
|
27
|
+
end
|
28
|
+
|
29
|
+
it "produces the correct output" do
|
30
|
+
s = JSONSelect(File.read(selector).strip)
|
31
|
+
e = []
|
32
|
+
Yajl::Parser.parse(File.read(output)) { |o| e << o }
|
33
|
+
s.evaluate(input).should == e
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
## JSONSelect Conformance Tests.
|
2
|
+
|
3
|
+
Test documents have a suffix of `.json`, like `basic.json`.
|
4
|
+
|
5
|
+
Selectors to be applied to test documents have the document name,
|
6
|
+
followed by an underbar, followed by a description of the test, with
|
7
|
+
a `.selector` file name suffix, like `basic_grouping.selector`.
|
8
|
+
|
9
|
+
Expected output files have the same name as the `.selector` file,
|
10
|
+
but have a `.output` suffix, like `basic_grouping.output`.
|
11
|
+
|
12
|
+
Expected output files contain a stream of JSON objects that are what
|
13
|
+
is expected to be produced when a given selector is applied to a given
|
14
|
+
document.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
basic.json
|
2
|
+
basic_first-child.output
|
3
|
+
basic_first-child.selector
|
4
|
+
basic_grouping.output
|
5
|
+
basic_grouping.selector
|
6
|
+
basic_id.output
|
7
|
+
basic_id.selector
|
8
|
+
basic_id_multiple.output
|
9
|
+
basic_id_multiple.selector
|
10
|
+
basic_id_quotes.output
|
11
|
+
basic_id_quotes.selector
|
12
|
+
basic_id_with_type.output
|
13
|
+
basic_id_with_type.selector
|
14
|
+
basic_last-child.output
|
15
|
+
basic_last-child.selector
|
16
|
+
basic_nth-child-2.output
|
17
|
+
basic_nth-child-2.selector
|
18
|
+
basic_nth-child.output
|
19
|
+
basic_nth-child.selector
|
20
|
+
basic_nth-last-child.output
|
21
|
+
basic_nth-last-child.selector
|
22
|
+
basic_root_pseudo.output
|
23
|
+
basic_root_pseudo.selector
|
24
|
+
basic_type.output
|
25
|
+
basic_type.selector
|
26
|
+
basic_type2.output
|
27
|
+
basic_type2.selector
|
28
|
+
basic_type3.output
|
29
|
+
basic_type3.selector
|
30
|
+
basic_universal.output
|
31
|
+
basic_universal.selector
|
@@ -0,0 +1,31 @@
|
|
1
|
+
{
|
2
|
+
"name": {
|
3
|
+
"first": "Lloyd",
|
4
|
+
"last": "Hilaiel"
|
5
|
+
},
|
6
|
+
"favoriteColor": "yellow",
|
7
|
+
"languagesSpoken": [
|
8
|
+
{
|
9
|
+
"language": "Bulgarian",
|
10
|
+
"level": "advanced"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"language": "English",
|
14
|
+
"level": "native"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"language": "Spanish",
|
18
|
+
"level": "beginner"
|
19
|
+
}
|
20
|
+
],
|
21
|
+
"seatingPreference": [
|
22
|
+
"window",
|
23
|
+
"aisle"
|
24
|
+
],
|
25
|
+
"drinkPreference": [
|
26
|
+
"beer",
|
27
|
+
"whiskey",
|
28
|
+
"wine"
|
29
|
+
],
|
30
|
+
"weight": 172
|
31
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<object>
|
2
|
+
<object id="name">
|
3
|
+
<string id="first">Lloyd</string>
|
4
|
+
<string id="last">Hilaiel</string>
|
5
|
+
</object>
|
6
|
+
<string id="favoriteColor">yellow</string>
|
7
|
+
<array id="languagesSpoken">
|
8
|
+
<object>
|
9
|
+
<string id="language">Bulgarian</string>
|
10
|
+
<string id="level">advanced</string>
|
11
|
+
</object>
|
12
|
+
<object>
|
13
|
+
<string id="language">English</string>
|
14
|
+
<string id="level">native</string>
|
15
|
+
</object>
|
16
|
+
<object>
|
17
|
+
<string id="language">Spanish</string>
|
18
|
+
<string id="level">beginner</string>
|
19
|
+
</object>
|
20
|
+
</array>
|
21
|
+
<array id="seatingPreference">
|
22
|
+
<string>window</string>
|
23
|
+
<string>aisle</string>
|
24
|
+
</array>
|
25
|
+
<array id="drinkPreference">
|
26
|
+
<string>beer</string>
|
27
|
+
<string>whiskey</string>
|
28
|
+
<string>wine</string>
|
29
|
+
</array>
|
30
|
+
<number id="weight">172</number>
|
31
|
+
</object>
|
@@ -0,0 +1 @@
|
|
1
|
+
string.level,number
|
@@ -0,0 +1 @@
|
|
1
|
+
"yellow"
|
@@ -0,0 +1 @@
|
|
1
|
+
.favoriteColor
|
@@ -0,0 +1 @@
|
|
1
|
+
.language
|
@@ -0,0 +1 @@
|
|
1
|
+
."weight"
|
@@ -0,0 +1 @@
|
|
1
|
+
"yellow"
|
@@ -0,0 +1 @@
|
|
1
|
+
string.favoriteColor
|