json_select 0.1.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/.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
|