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.
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
+ ]