json_select 0.1.2 → 0.1.3

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.
@@ -1,7 +1,7 @@
1
1
  rvm:
2
- - 1.8.7
2
+ # - 1.8.7
3
3
  - 1.9.1
4
4
  - 1.9.2
5
5
  - jruby
6
- - rbx
7
- - ree
6
+ # - rbx
7
+ # - ree
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # JSONSelect
1
+ # JSONSelect [![Build Status](http://travis-ci.org/fd/json_select.png)](http://travis-ci.org/fd/json_select)
2
2
 
3
3
  **CSS-like selectors for JSON.**
4
4
 
@@ -48,7 +48,9 @@ json = { # This would normally be loaded with something like yajl-ruby
48
48
  "weight" => 172
49
49
  }
50
50
 
51
- JSONSelect('string:first-child').match(json) # => ["Lloyd", "Bulgarian", "English", "Spanish", "window", "beer"]
51
+ JSONSelect('string:first-child').test(json) # => true
52
+ JSONSelect('string:first-child').match(json) # => "window"
53
+ JSONSelect('string:first-child').matches(json) # => ["window", "beer"]
52
54
  ```
53
55
 
54
56
  ## Note on Patches/Pull Requests
@@ -5,6 +5,12 @@ class JSONSelect
5
5
  require 'json_select/version'
6
6
  require 'json_select/selector_parser'
7
7
  require 'json_select/selector'
8
+
9
+ require 'json_select/helpers/size'
10
+ require 'json_select/helpers/key'
11
+ require 'json_select/helpers/type'
12
+ require 'json_select/helpers/depth'
13
+ require 'json_select/helpers/position'
8
14
 
9
15
  module Ast
10
16
  require 'json_select/ast/combination_selector'
@@ -0,0 +1,7 @@
1
+ module JSONSelect::DepthHelpers
2
+
3
+ def is_root(object, test, key, idx, size, depth)
4
+ depth == 0
5
+ end
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+ module JSONSelect::KeyHelpers
2
+
3
+ def has_class(object, test, key, idx, size, depth)
4
+ test[:n] == key.to_s
5
+ end
6
+
7
+ end
@@ -0,0 +1,24 @@
1
+ module JSONSelect::PositionHelpers
2
+
3
+ def nth_child(object, test, key, idx, size, depth)
4
+ return false unless idx and size
5
+
6
+ idx += 1
7
+
8
+ a = test[:a]
9
+ b = test[:b]
10
+
11
+ if a == 0
12
+ (b == idx)
13
+ else
14
+ (((idx - b) % a) == 0) and ((idx * a + b) >= 0)
15
+ end
16
+ end
17
+
18
+ def nth_last_child(object, test, key, idx, size, depth)
19
+ return false unless idx and size
20
+
21
+ nth_child(object, test, key, (size - idx) - 1, size, depth)
22
+ end
23
+
24
+ end
@@ -0,0 +1,24 @@
1
+ module JSONSelect::SizeHelpers
2
+
3
+ def only_child(object, test, key, idx, size, depth)
4
+ return false unless size
5
+
6
+ size == 1
7
+ end
8
+
9
+ def empty(object, test, key, idx, size, depth)
10
+ return false unless size
11
+
12
+ case object
13
+ when Array then return object.empty?
14
+ else
15
+ if object.respond_to?(:json_select_each)
16
+ object.json_select_each { return false }
17
+ return true
18
+ end
19
+ end
20
+
21
+ return false
22
+ end
23
+
24
+ end
@@ -0,0 +1,31 @@
1
+ module JSONSelect::TypeHelpers
2
+
3
+ def instance_of_type(object, test, key, idx, size, depth)
4
+ test[:n] == type_of(object)
5
+ end
6
+
7
+ private
8
+
9
+ def type_of(object)
10
+ if object.respond_to?(:json_select_each)
11
+ return 'array'
12
+ end
13
+
14
+ if object.respond_to?(:json_select_each_pair)
15
+ return 'object'
16
+ end
17
+
18
+ case object
19
+ when Hash then 'object'
20
+ when Array then 'array'
21
+ when String then 'string'
22
+ when Symbol then 'string'
23
+ when Numeric then 'number'
24
+ when TrueClass then 'boolean'
25
+ when FalseClass then 'boolean'
26
+ when NilClass then 'null'
27
+ else raise "Invalid object of class #{object.class} for JSONSelect: #{object.inspect}"
28
+ end
29
+ end
30
+
31
+ end
@@ -42,6 +42,19 @@ class JSONSelect
42
42
  raise ArgumentError, "Expected a string for ast"
43
43
 
44
44
  end
45
+
46
+ @helpers = Module.new
47
+ @helpers.send(:extend,
48
+ JSONSelect::KeyHelpers,
49
+ JSONSelect::TypeHelpers,
50
+ JSONSelect::SizeHelpers,
51
+ JSONSelect::DepthHelpers,
52
+ JSONSelect::PositionHelpers)
53
+
54
+ @helper_methods = {}
55
+ (@helpers.public_methods - Module.public_methods).map do |name|
56
+ @helper_methods[name.to_sym] = @helpers.method(name)
57
+ end
45
58
  end
46
59
 
47
60
  # Returns the first matching child in `object`
@@ -79,32 +92,6 @@ class JSONSelect
79
92
 
80
93
  private
81
94
 
82
- # function forEach(sel, obj, fun, id, num, tot) {
83
- # var a = (sel[0] === ',') ? sel.slice(1) : [sel];
84
- # var a0 = [];
85
- # var call = false;
86
- # for (var i = 0; i < a.length; i++) {
87
- # var x = mn(obj, a[i], id, num, tot);
88
- # if (x[0]) call = true;
89
- # for (var j = 0; j < x[1].length; j++) a0.push(x[1][j]);
90
- # }
91
- # if (a0.length && typeof obj === 'object') {
92
- # if (a0.length >= 1) a0.unshift(",");
93
- # if (isArray(obj)) {
94
- # for (var i = 0; i < obj.length; i++) forEach(a0, obj[i], fun, undefined, i, obj.length);
95
- # } else {
96
- # // it's a shame to do this for :last-child and other
97
- # // properties which count from the end when we don't
98
- # // even know if they're present. Also, the stream
99
- # // parser is going to be pissed.
100
- # var l = 0;
101
- # for (var k in obj) if (obj.hasOwnProperty(k)) l++;
102
- # var i = 0;
103
- # for (var k in obj) if (obj.hasOwnProperty(k)) forEach(a0, obj[k], fun, k, i++, l);
104
- # }
105
- # }
106
- # if (call && fun) fun(obj);
107
- # };
108
95
  def _each(selector, object, id, number, total, depth, &block)
109
96
  a0 = (selector[0] == ',' ? selector[1..-1] : [selector])
110
97
  a1 = []
@@ -131,27 +118,33 @@ private
131
118
 
132
119
  when Hash
133
120
  a1.unshift(',')
134
- size = object.size
135
121
 
136
- object.each_with_index do |(key, child), idx|
137
- _each(a1, child, key, idx, size, depth + 1, &block)
122
+ object.each do |key, child|
123
+ _each(a1, child, key, nil, nil, depth + 1, &block)
138
124
  end
139
125
 
140
126
  else
141
127
  if object.respond_to?(:json_select_each)
142
128
  children = []
143
- object.json_select_each do |key, value|
144
- children << [key, value]
129
+ object.json_select_each do |value|
130
+ children << value
145
131
  end
146
132
 
147
133
  a1.unshift(',')
148
134
  size = children.size
149
135
 
150
- children.each_with_index do |(key, child), idx|
151
- _each(a1, child, key, idx, size, depth + 1, &block)
136
+ children.each_with_index do |child, idx|
137
+ _each(a1, child, nil, idx, size, depth + 1, &block)
138
+ end
139
+
140
+ elsif object.respond_to?(:json_select_each_pair)
141
+ a1.unshift(',')
142
+
143
+ object.json_select_each_pair do |key, child|
144
+ _each(a1, child, key, nil, nil, depth + 1, &block)
152
145
  end
146
+
153
147
  end
154
-
155
148
  end
156
149
  end
157
150
 
@@ -160,34 +153,6 @@ private
160
153
  end
161
154
  end
162
155
 
163
-
164
- # function mn(node, sel, id, num, tot) {
165
- # var sels = [];
166
- # var cs = (sel[0] === '>') ? sel[1] : sel[0];
167
- # var m = true;
168
- # if (cs.type) m = m && (cs.type === mytypeof(node));
169
- # if (cs.id) m = m && (cs.id === id);
170
- # if (m && cs.pf) {
171
- # if (cs.pf === ":nth-last-child") num = tot - num;
172
- # else num++;
173
- # if (cs.a === 0) {
174
- # m = cs.b === num;
175
- # } else {
176
- # m = (!((num - cs.b) % cs.a) && ((num*cs.a + cs.b) >= 0));
177
- # }
178
- # }
179
- #
180
- # // should we repeat this selector for descendants?
181
- # if (sel[0] !== '>' && sel[0].pc !== ":root") sels.push(sel);
182
- #
183
- # if (m) {
184
- # // is there a fragment that we should pass down?
185
- # if (sel[0] === '>') { if (sel.length > 2) { m = false; sels.push(sel.slice(2)); } }
186
- # else if (sel.length > 1) { m = false; sels.push(sel.slice(1)); }
187
- # }
188
- #
189
- # return [m, sels];
190
- # }
191
156
  def _match(object, selector, id, number, total, depth)
192
157
  selectors = []
193
158
  current_selector = (selector[0] == :> ? selector[1] : selector[0])
@@ -200,7 +165,7 @@ private
200
165
  end
201
166
 
202
167
  if match
203
- match = !!send(test[:f], object, test, id, number, total, depth)
168
+ match = !!@helper_methods[test[:f].to_sym].call(object, test, id, number, total, depth)
204
169
  end
205
170
  end
206
171
 
@@ -235,70 +200,4 @@ private
235
200
  return [match, selectors]
236
201
  end
237
202
 
238
- def type_of(object)
239
- if object.respond_to?(:json_select_each)
240
- return 'object'
241
- end
242
-
243
- case object
244
- when Hash then 'object'
245
- when Array then 'array'
246
- when String then 'string'
247
- when Symbol then 'string'
248
- when Numeric then 'number'
249
- when TrueClass then 'boolean'
250
- when FalseClass then 'boolean'
251
- when NilClass then 'null'
252
- else raise "Invalid object of class #{object.class} for JSONSelect: #{object.inspect}"
253
- end
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
303
-
304
203
  end
@@ -1,3 +1,3 @@
1
1
  class JSONSelect
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -1,6 +1,2 @@
1
- "Lloyd"
2
- "Bulgarian"
3
- "English"
4
- "Spanish"
5
1
  "window"
6
2
  "beer"
@@ -1,6 +1,2 @@
1
- "Hilaiel"
2
- "advanced"
3
- "native"
4
- "beginner"
5
1
  "aisle"
6
2
  "wine"
@@ -1,12 +1,3 @@
1
- "Lloyd"
2
- "Hilaiel"
3
- "yellow"
4
- "Bulgarian"
5
- "advanced"
6
- "English"
7
- "native"
8
- "Spanish"
9
- "beginner"
10
1
  "window"
11
2
  "aisle"
12
3
  "beer"
@@ -1,7 +1,3 @@
1
- "Lloyd"
2
- "Bulgarian"
3
- "English"
4
- "Spanish"
5
1
  "window"
6
2
  "beer"
7
3
  "wine"
@@ -1,6 +1,2 @@
1
- "Hilaiel"
2
- "advanced"
3
- "native"
4
- "beginner"
5
1
  "aisle"
6
2
  "wine"
@@ -83,4 +83,4 @@
83
83
  "wine"
84
84
  ],
85
85
  "weight": 172
86
- }
86
+ }
@@ -12,9 +12,9 @@ describe "JSONSelect", "Ruby extensions" do
12
12
  should == :hello
13
13
  end
14
14
 
15
- it "treats Objects which respond to #json_select_each as Objects" do
15
+ it "treats Objects which respond to #json_select_each_pair as Objects" do
16
16
  class Person < Struct.new(:name, :age)
17
- def json_select_each
17
+ def json_select_each_pair
18
18
  yield(:name, self.name)
19
19
  yield(:age, self.age)
20
20
  end
@@ -25,4 +25,20 @@ describe "JSONSelect", "Ruby extensions" do
25
25
  should == 'Simon Menke'
26
26
  end
27
27
 
28
+ it "treats Objects which respond to #json_select_each as Arrays" do
29
+ class List
30
+ def initialize(items)
31
+ @items = items
32
+ end
33
+
34
+ def json_select_each
35
+ @items.each { |i| yield(i) }
36
+ end
37
+ end
38
+
39
+ JSONSelect('array.person string:first-child').
40
+ match(:person => List.new(%w( foo bar baz ))).
41
+ should == 'foo'
42
+ end
43
+
28
44
  end
metadata CHANGED
@@ -1,34 +1,39 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: json_select
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.2
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
5
+ version: 0.1.3
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Simon Menke
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-05-26 00:00:00.000000000Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
12
+
13
+ date: 2011-05-27 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
15
17
  name: treetop
16
- requirement: &70235358530860 !ruby/object:Gem::Requirement
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
17
20
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
22
25
  type: :runtime
23
- prerelease: false
24
- version_requirements: *70235358530860
26
+ version_requirements: *id001
25
27
  description: JSONSelect implementation for Ruby
26
- email:
28
+ email:
27
29
  - simon.menke@gmail.com
28
30
  executables: []
31
+
29
32
  extensions: []
33
+
30
34
  extra_rdoc_files: []
31
- files:
35
+
36
+ files:
32
37
  - .gitignore
33
38
  - .travis.yml
34
39
  - Gemfile
@@ -48,6 +53,11 @@ files:
48
53
  - lib/json_select/ast/simple_selector.rb
49
54
  - lib/json_select/ast/type_selector.rb
50
55
  - lib/json_select/ast/universal_selector.rb
56
+ - lib/json_select/helpers/depth.rb
57
+ - lib/json_select/helpers/key.rb
58
+ - lib/json_select/helpers/position.rb
59
+ - lib/json_select/helpers/size.rb
60
+ - lib/json_select/helpers/type.rb
51
61
  - lib/json_select/selector.rb
52
62
  - lib/json_select/selector_parser.rb
53
63
  - lib/json_select/selector_parser.tt
@@ -110,31 +120,35 @@ files:
110
120
  - spec/fixtures/basic_universal.selector
111
121
  - spec/ruby_extensions_spec.rb
112
122
  - spec/spec_helper.rb
123
+ has_rdoc: true
113
124
  homepage: http://github.com/fd/json_select
114
125
  licenses: []
126
+
115
127
  post_install_message:
116
128
  rdoc_options: []
117
- require_paths:
129
+
130
+ require_paths:
118
131
  - lib
119
- required_ruby_version: !ruby/object:Gem::Requirement
132
+ required_ruby_version: !ruby/object:Gem::Requirement
120
133
  none: false
121
- requirements:
122
- - - ! '>='
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: "0"
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
139
  none: false
127
- requirements:
128
- - - ! '>='
129
- - !ruby/object:Gem::Version
130
- version: '0'
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: "0"
131
144
  requirements: []
145
+
132
146
  rubyforge_project: json_select
133
- rubygems_version: 1.7.2
147
+ rubygems_version: 1.6.2
134
148
  signing_key:
135
149
  specification_version: 3
136
150
  summary: JSONSelect implementation for Ruby
137
- test_files:
151
+ test_files:
138
152
  - spec/conformance_spec.rb
139
153
  - spec/fixtures/README.md
140
154
  - spec/fixtures/alltests.txt