json_select 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +7 -0
  3. data/LICENSE +20 -0
  4. data/README.md +67 -0
  5. data/Rakefile +18 -0
  6. data/json_select.gemspec +23 -0
  7. data/lib/json_select.rb +35 -0
  8. data/lib/json_select/ast/combination_selector.rb +14 -0
  9. data/lib/json_select/ast/complex_expr.rb +27 -0
  10. data/lib/json_select/ast/even_expr.rb +7 -0
  11. data/lib/json_select/ast/hash_selector.rb +12 -0
  12. data/lib/json_select/ast/odd_expr.rb +7 -0
  13. data/lib/json_select/ast/pseudo_selector.rb +24 -0
  14. data/lib/json_select/ast/selector_group.rb +17 -0
  15. data/lib/json_select/ast/simple_expr.rb +7 -0
  16. data/lib/json_select/ast/simple_selector.rb +23 -0
  17. data/lib/json_select/ast/type_selector.rb +8 -0
  18. data/lib/json_select/ast/universal_selector.rb +7 -0
  19. data/lib/json_select/parser.rb +19 -0
  20. data/lib/json_select/selector.rb +176 -0
  21. data/lib/json_select/selector_parser.rb +1251 -0
  22. data/lib/json_select/selector_parser.tt +161 -0
  23. data/lib/json_select/version.rb +3 -0
  24. data/spec/conformance_spec.rb +41 -0
  25. data/spec/fixtures/README.md +14 -0
  26. data/spec/fixtures/alltests.txt +31 -0
  27. data/spec/fixtures/basic.json +31 -0
  28. data/spec/fixtures/basic.xml +31 -0
  29. data/spec/fixtures/basic_first-child.ast +6 -0
  30. data/spec/fixtures/basic_first-child.output +6 -0
  31. data/spec/fixtures/basic_first-child.selector +2 -0
  32. data/spec/fixtures/basic_grouping.ast +12 -0
  33. data/spec/fixtures/basic_grouping.output +4 -0
  34. data/spec/fixtures/basic_grouping.selector +1 -0
  35. data/spec/fixtures/basic_id.ast +3 -0
  36. data/spec/fixtures/basic_id.output +1 -0
  37. data/spec/fixtures/basic_id.selector +1 -0
  38. data/spec/fixtures/basic_id_multiple.ast +3 -0
  39. data/spec/fixtures/basic_id_multiple.output +3 -0
  40. data/spec/fixtures/basic_id_multiple.selector +1 -0
  41. data/spec/fixtures/basic_id_quotes.ast +3 -0
  42. data/spec/fixtures/basic_id_quotes.output +2 -0
  43. data/spec/fixtures/basic_id_quotes.selector +1 -0
  44. data/spec/fixtures/basic_id_with_type.ast +4 -0
  45. data/spec/fixtures/basic_id_with_type.output +1 -0
  46. data/spec/fixtures/basic_id_with_type.selector +1 -0
  47. data/spec/fixtures/basic_last-child.ast +6 -0
  48. data/spec/fixtures/basic_last-child.output +6 -0
  49. data/spec/fixtures/basic_last-child.selector +2 -0
  50. data/spec/fixtures/basic_nth-child-2.ast +6 -0
  51. data/spec/fixtures/basic_nth-child-2.output +13 -0
  52. data/spec/fixtures/basic_nth-child-2.selector +1 -0
  53. data/spec/fixtures/basic_nth-child.ast +6 -0
  54. data/spec/fixtures/basic_nth-child.output +7 -0
  55. data/spec/fixtures/basic_nth-child.selector +1 -0
  56. data/spec/fixtures/basic_nth-last-child.ast +6 -0
  57. data/spec/fixtures/basic_nth-last-child.output +6 -0
  58. data/spec/fixtures/basic_nth-last-child.selector +1 -0
  59. data/spec/fixtures/basic_root_pseudo.ast +3 -0
  60. data/spec/fixtures/basic_root_pseudo.output +31 -0
  61. data/spec/fixtures/basic_root_pseudo.selector +1 -0
  62. data/spec/fixtures/basic_type.ast +3 -0
  63. data/spec/fixtures/basic_type.output +14 -0
  64. data/spec/fixtures/basic_type.selector +1 -0
  65. data/spec/fixtures/basic_type2.ast +3 -0
  66. data/spec/fixtures/basic_type2.output +1 -0
  67. data/spec/fixtures/basic_type2.selector +1 -0
  68. data/spec/fixtures/basic_type3.ast +3 -0
  69. data/spec/fixtures/basic_type3.output +47 -0
  70. data/spec/fixtures/basic_type3.selector +1 -0
  71. data/spec/fixtures/basic_universal.ast +2 -0
  72. data/spec/fixtures/basic_universal.output +85 -0
  73. data/spec/fixtures/basic_universal.selector +1 -0
  74. data/spec/spec_helper.rb +6 -0
  75. 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,3 @@
1
+ module JSONSelect
2
+ VERSION = "0.1.0"
3
+ 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,6 @@
1
+ [ { "type" : "string"
2
+ , "pseudo_function" : "nth-child"
3
+ , "a" : 0
4
+ , "b" : 1
5
+ }
6
+ ]
@@ -0,0 +1,6 @@
1
+ "Lloyd"
2
+ "Bulgarian"
3
+ "English"
4
+ "Spanish"
5
+ "window"
6
+ "beer"
@@ -0,0 +1,2 @@
1
+ string:first-child
2
+
@@ -0,0 +1,12 @@
1
+ [ ","
2
+
3
+ , [ { "type" : "string"
4
+ , "class" : "level"
5
+ }
6
+ ]
7
+
8
+ , [ { "type" : "number"
9
+ }
10
+ ]
11
+
12
+ ]
@@ -0,0 +1,4 @@
1
+ "advanced"
2
+ "native"
3
+ "beginner"
4
+ 172
@@ -0,0 +1 @@
1
+ string.level,number
@@ -0,0 +1,3 @@
1
+ [ { "class" : "favoriteColor"
2
+ }
3
+ ]
@@ -0,0 +1 @@
1
+ "yellow"
@@ -0,0 +1 @@
1
+ .favoriteColor
@@ -0,0 +1,3 @@
1
+ [ { "class" : "language"
2
+ }
3
+ ]
@@ -0,0 +1,3 @@
1
+ "Bulgarian"
2
+ "English"
3
+ "Spanish"
@@ -0,0 +1 @@
1
+ .language
@@ -0,0 +1,3 @@
1
+ [ { "class" : "weight"
2
+ }
3
+ ]
@@ -0,0 +1,2 @@
1
+ 172
2
+
@@ -0,0 +1 @@
1
+ ."weight"
@@ -0,0 +1,4 @@
1
+ [ { "class" : "favoriteColor"
2
+ , "type" : "string"
3
+ }
4
+ ]
@@ -0,0 +1 @@
1
+ "yellow"
@@ -0,0 +1 @@
1
+ string.favoriteColor
@@ -0,0 +1,6 @@
1
+ [ { "type" : "string"
2
+ , "pseudo_function" : "nth-last-child"
3
+ , "a" : 0
4
+ , "b" : 1
5
+ }
6
+ ]
@@ -0,0 +1,6 @@
1
+ "Hilaiel"
2
+ "advanced"
3
+ "native"
4
+ "beginner"
5
+ "aisle"
6
+ "wine"
@@ -0,0 +1,2 @@
1
+ string:last-child
2
+
@@ -0,0 +1,6 @@
1
+ [ { "type" : "string"
2
+ , "pseudo_function" : "nth-child"
3
+ , "a" : -1
4
+ , "b" : 2
5
+ }
6
+ ]