json_select 0.1.1 → 0.1.2

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.
@@ -3,9 +3,9 @@ module JSONSelect::Ast::HashSelector
3
3
  def to_ast
4
4
  tv = self.text_value[1..-1]
5
5
  if tv[0,1] == '"'
6
- { :class => eval(tv) }
6
+ { :f => :has_class, :n => eval(tv) }
7
7
  else
8
- { :class => tv }
8
+ { :f => :has_class, :n => tv }
9
9
  end
10
10
  end
11
11
 
@@ -2,20 +2,23 @@ module JSONSelect::Ast::PseudoSelector
2
2
 
3
3
  def to_ast
4
4
  if respond_to?(:e)
5
- ast = { :pseudo_function => a.text_value, :a => 0 , :b => 0 }
6
- ast.merge!(e.to_ast)
7
- ast
5
+ test = { :f => a.text_value.gsub('-', '_') }
6
+ test.merge!(e.to_ast)
7
+ test
8
8
  else
9
9
  case a.text_value
10
10
 
11
11
  when 'first-child'
12
- { :pseudo_function => 'nth-child', :a => 0, :b => 1 }
12
+ { :f => :nth_child, :a => 0, :b => 1 }
13
13
 
14
14
  when 'last-child'
15
- { :pseudo_function => 'nth-last-child', :a => 0, :b => 1 }
15
+ { :f => :nth_last_child, :a => 0, :b => 1 }
16
+
17
+ when 'root'
18
+ { :f => :is_root }
16
19
 
17
20
  else
18
- { :pseudo_class => a.text_value }
21
+ { :f => a.text_value.gsub('-', '_') }
19
22
 
20
23
  end
21
24
  end
@@ -1,23 +1,26 @@
1
1
  module JSONSelect::Ast::SimpleSelector
2
2
 
3
3
  def to_ast
4
- ast = {}
4
+ tests = []
5
+ node = {:tests => tests}
5
6
 
6
7
  if respond_to?(:a) and respond_to?(:b)
7
- ast.merge! a.to_ast
8
+ tests << a.to_ast
8
9
 
9
10
  b.elements.each do |s|
10
- ast.merge!(s.to_ast)
11
+ tests << s.to_ast
11
12
  end
12
13
 
13
14
  else
14
15
  self.elements.each do |s|
15
- ast.merge!(s.to_ast)
16
+ tests << s.to_ast
16
17
  end
17
18
 
18
19
  end
19
20
 
20
- ast
21
+ tests.compact!
22
+
23
+ node
21
24
  end
22
25
 
23
26
  end
@@ -2,7 +2,7 @@ module JSONSelect::Ast::TypeSelector
2
2
 
3
3
  # `object` | `array` | `number` | `string` | `boolean` | `null`
4
4
  def to_ast
5
- { :type => self.text_value }
5
+ { :f => :instance_of_type, :n => self.text_value }
6
6
  end
7
7
 
8
8
  end
@@ -1,7 +1,7 @@
1
1
  module JSONSelect::Ast::UniversalSelector
2
2
 
3
3
  def to_ast
4
- {}
4
+ nil
5
5
  end
6
6
 
7
7
  end
@@ -46,7 +46,7 @@ class JSONSelect
46
46
 
47
47
  # Returns the first matching child in `object`
48
48
  def match(object)
49
- _each(@ast, object, nil, nil, nil) do |object|
49
+ _each(@ast, object, nil, nil, nil, 0) do |object|
50
50
  return object
51
51
  end
52
52
 
@@ -59,7 +59,7 @@ class JSONSelect
59
59
  def matches(object)
60
60
  matches = []
61
61
 
62
- _each(@ast, object, nil, nil, nil) do |object|
62
+ _each(@ast, object, nil, nil, nil, 0) do |object|
63
63
  matches << object
64
64
  end
65
65
 
@@ -68,7 +68,7 @@ class JSONSelect
68
68
 
69
69
  # Returns true if `object` has any matching children.
70
70
  def test(object)
71
- _each(@ast, object, nil, nil, nil) do |object|
71
+ _each(@ast, object, nil, nil, nil, 0) do |object|
72
72
  return true
73
73
  end
74
74
 
@@ -105,14 +105,14 @@ private
105
105
  # }
106
106
  # if (call && fun) fun(obj);
107
107
  # };
108
- def _each(selector, object, id, number, total, &block)
108
+ def _each(selector, object, id, number, total, depth, &block)
109
109
  a0 = (selector[0] == ',' ? selector[1..-1] : [selector])
110
110
  a1 = []
111
111
 
112
112
  call = false
113
113
 
114
114
  a0.each do |selector|
115
- ok, extra = _match(object, selector, id, number, total)
115
+ ok, extra = _match(object, selector, id, number, total, depth)
116
116
 
117
117
  call = true if ok
118
118
  a1.concat extra
@@ -126,7 +126,7 @@ private
126
126
  size = object.size
127
127
 
128
128
  object.each_with_index do |child, idx|
129
- _each(a1, child, nil, idx, size, &block)
129
+ _each(a1, child, nil, idx, size, depth + 1, &block)
130
130
  end
131
131
 
132
132
  when Hash
@@ -134,7 +134,7 @@ private
134
134
  size = object.size
135
135
 
136
136
  object.each_with_index do |(key, child), idx|
137
- _each(a1, child, key, idx, size, &block)
137
+ _each(a1, child, key, idx, size, depth + 1, &block)
138
138
  end
139
139
 
140
140
  else
@@ -148,7 +148,7 @@ private
148
148
  size = children.size
149
149
 
150
150
  children.each_with_index do |(key, child), idx|
151
- _each(a1, child, key, idx, size, &block)
151
+ _each(a1, child, key, idx, size, depth + 1, &block)
152
152
  end
153
153
  end
154
154
 
@@ -188,56 +188,54 @@ private
188
188
  #
189
189
  # return [m, sels];
190
190
  # }
191
- def _match(object, selector, id, number, total)
191
+ def _match(object, selector, id, number, total, depth)
192
192
  selectors = []
193
193
  current_selector = (selector[0] == :> ? selector[1] : selector[0])
194
194
  match = true
195
+ has_root_test = false
195
196
 
196
- if current_selector.key?(:type)
197
- match = (match and current_selector[:type] == _type_of(object))
198
- end
199
-
200
- if current_selector.key?(:class)
201
- match = (match and current_selector[:class] == id.to_s)
202
- end
203
-
204
- if match and current_selector.key?(:pseudo_function)
205
- pseudo_function = current_selector[:pseudo_function]
206
-
207
- if pseudo_function == 'nth-last-child'
208
- number = total - number
209
- else
210
- number += 1
197
+ current_selector[:tests].each do |test|
198
+ if test[:f] == :is_root
199
+ has_root_test = true
211
200
  end
212
-
213
- if current_selector[:a] == 0
214
- match = (current_selector[:b] == number)
215
- else
216
- # WTF!
217
- match = ((((number - current_selector[:b]) % current_selector[:a]) == 0) && ((number * current_selector[:a] + current_selector[:b]) >= 0))
201
+
202
+ if match
203
+ match = !!send(test[:f], object, test, id, number, total, depth)
218
204
  end
219
205
  end
220
206
 
221
- if Hash === selector[0] and selector[0][:pseudo_class] != 'root'
207
+ # continue search for decendants
208
+ if Hash === selector[0] and !has_root_test
222
209
  selectors.push selector
223
210
  end
224
211
 
225
- if match
226
- if selector[0] == :>
227
- if selector.length > 2
228
- match = false
229
- selectors.push selector[2..-1]
230
- end
231
- elsif selector.length > 1
232
- match = false
233
- selectors.push selector[1..-1]
234
- end
212
+ # break search for terminals
213
+ if selector.size <= 1
214
+ return [match, selectors]
215
+ end
216
+
217
+ # break search (no match)
218
+ unless match
219
+ return [match, selectors]
220
+ end
221
+
222
+ # continue search for decendants
223
+ unless selector[0] == :>
224
+ match = false
225
+ selectors.push selector[1..-1]
226
+ return [match, selectors]
227
+ end
228
+
229
+ # continue search for children
230
+ if selector.length > 2
231
+ match = false
232
+ selectors.push selector[2..-1]
235
233
  end
236
234
 
237
235
  return [match, selectors]
238
236
  end
239
237
 
240
- def _type_of(object)
238
+ def type_of(object)
241
239
  if object.respond_to?(:json_select_each)
242
240
  return 'object'
243
241
  end
@@ -254,5 +252,53 @@ private
254
252
  else raise "Invalid object of class #{object.class} for JSONSelect: #{object.inspect}"
255
253
  end
256
254
  end
255
+
256
+ def only_child(object, test, key, idx, size, depth)
257
+ size == 1
258
+ end
259
+
260
+ def empty(object, test, key, idx, size, depth)
261
+ case object
262
+ when Array then return object.empty?
263
+ when Hash then return object.empty?
264
+ else
265
+ if object.respond_to?(:json_select_each)
266
+ object.json_select_each { return false }
267
+ return true
268
+ end
269
+ end
270
+ return false
271
+ end
272
+
273
+ def is_root(object, test, key, idx, size, depth)
274
+ depth == 0
275
+ end
276
+
277
+ def instance_of_type(object, test, key, idx, size, depth)
278
+ test[:n] == type_of(object)
279
+ end
280
+
281
+ def has_class(object, test, key, idx, size, depth)
282
+ test[:n] == key.to_s
283
+ end
284
+
285
+ def nth_child(object, test, key, idx, size, depth)
286
+ return false unless idx
287
+
288
+ idx += 1
289
+
290
+ a = test[:a]
291
+ b = test[:b]
292
+
293
+ if a == 0
294
+ (b == idx)
295
+ else
296
+ (((idx - b) % a) == 0) and ((idx * a + b) >= 0)
297
+ end
298
+ end
299
+
300
+ def nth_last_child(object, test, key, idx, size, depth)
301
+ nth_child(object, test, key, (size - idx) - 1, size, depth)
302
+ end
257
303
 
258
304
  end
@@ -794,8 +794,19 @@ module JSONSelect::Selector
794
794
  if r4
795
795
  r0 = r4
796
796
  else
797
- @index = i0
798
- r0 = nil
797
+ if has_terminal?('empty', false, index)
798
+ r5 = instantiate_node(SyntaxNode,input, index...(index + 5))
799
+ @index += 5
800
+ else
801
+ terminal_parse_failure('empty')
802
+ r5 = nil
803
+ end
804
+ if r5
805
+ r0 = r5
806
+ else
807
+ @index = i0
808
+ r0 = nil
809
+ end
799
810
  end
800
811
  end
801
812
  end
@@ -69,7 +69,7 @@ grammar JSONSelectSelector
69
69
  # pseudo_class_name
70
70
  # : `root` | `first-child` | `last-child` | `only-child`
71
71
  rule pseudo_class_name
72
- 'root' / 'first-child' / 'last-child' / 'only-child'
72
+ 'root' / 'first-child' / 'last-child' / 'only-child' / 'empty'
73
73
  end
74
74
 
75
75
  # pseudo_function_name
@@ -1,3 +1,3 @@
1
1
  class JSONSelect
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -1,6 +1,14 @@
1
- [ { "class" : "name"
1
+ [ { "tests" :
2
+ [ { "f" : "has_class"
3
+ , "n" : "name"
4
+ }
5
+ ]
2
6
  }
3
7
  , ">"
4
- , { "class" : "first"
8
+ , { "tests" :
9
+ [ { "f" : "has_class"
10
+ , "n" : "first"
11
+ }
12
+ ]
5
13
  }
6
14
  ]
@@ -1,5 +1,13 @@
1
- [ { "class" : "name"
1
+ [ { "tests" :
2
+ [ { "f" : "has_class"
3
+ , "n" : "name"
4
+ }
5
+ ]
2
6
  }
3
- , { "class" : "first"
7
+ , { "tests" :
8
+ [ { "f" : "has_class"
9
+ , "n" : "first"
10
+ }
11
+ ]
4
12
  }
5
13
  ]
@@ -1,6 +1,11 @@
1
- [ { "type" : "string"
2
- , "pseudo_function" : "nth-child"
3
- , "a" : 0
4
- , "b" : 1
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "string"
4
+ }
5
+ , { "f" : "nth_child"
6
+ , "a" : 0
7
+ , "b" : 1
8
+ }
9
+ ]
5
10
  }
6
11
  ]
@@ -1,12 +1,22 @@
1
1
  [ ","
2
2
 
3
- , [ { "type" : "string"
4
- , "class" : "level"
3
+ , [ { "tests" :
4
+ [ { "f" : "instance_of_type"
5
+ , "n" : "string"
6
+ }
7
+ , { "f" : "has_class"
8
+ , "n" : "level"
9
+ }
10
+ ]
5
11
  }
6
12
  ]
7
-
8
- , [ { "type" : "number"
13
+
14
+ , [ { "tests" :
15
+ [ { "f" : "instance_of_type"
16
+ , "n" : "number"
17
+ }
18
+ ]
9
19
  }
10
20
  ]
11
-
21
+
12
22
  ]
@@ -1,3 +1,7 @@
1
- [ { "class" : "favoriteColor"
1
+ [ { "tests" :
2
+ [ { "f" : "has_class"
3
+ , "n" : "favoriteColor"
4
+ }
5
+ ]
2
6
  }
3
7
  ]
@@ -1,3 +1,7 @@
1
- [ { "class" : "language"
1
+ [ { "tests" :
2
+ [ { "f" : "has_class"
3
+ , "n" : "language"
4
+ }
5
+ ]
2
6
  }
3
7
  ]
@@ -1,3 +1,7 @@
1
- [ { "class" : "weight"
1
+ [ { "tests" :
2
+ [ { "f" : "has_class"
3
+ , "n" : "weight"
4
+ }
5
+ ]
2
6
  }
3
7
  ]
@@ -1,4 +1,10 @@
1
- [ { "class" : "favoriteColor"
2
- , "type" : "string"
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "string"
4
+ }
5
+ , { "f" : "has_class"
6
+ , "n" : "favoriteColor"
7
+ }
8
+ ]
3
9
  }
4
10
  ]
@@ -1,6 +1,11 @@
1
- [ { "type" : "string"
2
- , "pseudo_function" : "nth-last-child"
3
- , "a" : 0
4
- , "b" : 1
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "string"
4
+ }
5
+ , { "f" : "nth_last_child"
6
+ , "a" : 0
7
+ , "b" : 1
8
+ }
9
+ ]
5
10
  }
6
- ]
11
+ ]
@@ -1,6 +1,11 @@
1
- [ { "type" : "string"
2
- , "pseudo_function" : "nth-child"
3
- , "a" : -1
4
- , "b" : 2
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "string"
4
+ }
5
+ , { "f" : "nth_child"
6
+ , "a" : -1
7
+ , "b" : 2
8
+ }
9
+ ]
5
10
  }
6
11
  ]
@@ -1,6 +1,11 @@
1
- [ { "type" : "string"
2
- , "pseudo_function" : "nth-child"
3
- , "a" : 2
4
- , "b" : 1
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "string"
4
+ }
5
+ , { "f" : "nth_child"
6
+ , "a" : 2
7
+ , "b" : 1
8
+ }
9
+ ]
5
10
  }
6
11
  ]
@@ -1,6 +1,11 @@
1
- [ { "type" : "string"
2
- , "pseudo_function" : "nth-last-child"
3
- , "a" : 0
4
- , "b" : 1
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "string"
4
+ }
5
+ , { "f" : "nth_last_child"
6
+ , "a" : 0
7
+ , "b" : 1
8
+ }
9
+ ]
5
10
  }
6
11
  ]
@@ -1,3 +1,6 @@
1
- [ { "pseudo_class" : "root"
1
+ [ { "tests" :
2
+ [ { "f" : "is_root"
3
+ }
4
+ ]
2
5
  }
3
6
  ]
@@ -1,3 +1,7 @@
1
- [ { "type" : "string"
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "string"
4
+ }
5
+ ]
2
6
  }
3
7
  ]
@@ -1,3 +1,7 @@
1
- [ { "type" : "number"
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "number"
4
+ }
5
+ ]
2
6
  }
3
7
  ]
@@ -1,3 +1,7 @@
1
- [ { "type" : "object"
1
+ [ { "tests" :
2
+ [ { "f" : "instance_of_type"
3
+ , "n" : "object"
4
+ }
5
+ ]
2
6
  }
3
7
  ]
@@ -1,2 +1,5 @@
1
- [ { }
1
+ [ { "tests" :
2
+ [
3
+ ]
4
+ }
2
5
  ]
metadata CHANGED
@@ -1,39 +1,34 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: json_select
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
4
5
  prerelease:
5
- version: 0.1.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Simon Menke
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-05-24 00:00:00 +02:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
12
+ date: 2011-05-26 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
17
15
  name: treetop
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &70235358530860 !ruby/object:Gem::Requirement
20
17
  none: false
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
25
22
  type: :runtime
26
- version_requirements: *id001
23
+ prerelease: false
24
+ version_requirements: *70235358530860
27
25
  description: JSONSelect implementation for Ruby
28
- email:
26
+ email:
29
27
  - simon.menke@gmail.com
30
28
  executables: []
31
-
32
29
  extensions: []
33
-
34
30
  extra_rdoc_files: []
35
-
36
- files:
31
+ files:
37
32
  - .gitignore
38
33
  - .travis.yml
39
34
  - Gemfile
@@ -115,35 +110,31 @@ files:
115
110
  - spec/fixtures/basic_universal.selector
116
111
  - spec/ruby_extensions_spec.rb
117
112
  - spec/spec_helper.rb
118
- has_rdoc: true
119
113
  homepage: http://github.com/fd/json_select
120
114
  licenses: []
121
-
122
115
  post_install_message:
123
116
  rdoc_options: []
124
-
125
- require_paths:
117
+ require_paths:
126
118
  - lib
127
- required_ruby_version: !ruby/object:Gem::Requirement
119
+ required_ruby_version: !ruby/object:Gem::Requirement
128
120
  none: false
129
- requirements:
130
- - - ">="
131
- - !ruby/object:Gem::Version
132
- version: "0"
133
- required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
126
  none: false
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: "0"
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
139
131
  requirements: []
140
-
141
132
  rubyforge_project: json_select
142
- rubygems_version: 1.6.2
133
+ rubygems_version: 1.7.2
143
134
  signing_key:
144
135
  specification_version: 3
145
136
  summary: JSONSelect implementation for Ruby
146
- test_files:
137
+ test_files:
147
138
  - spec/conformance_spec.rb
148
139
  - spec/fixtures/README.md
149
140
  - spec/fixtures/alltests.txt