djc 0.3.0 → 0.4.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/lib/djc.rb +82 -69
- metadata +2 -2
data/lib/djc.rb
CHANGED
@@ -12,47 +12,54 @@ module DJC
|
|
12
12
|
|
13
13
|
class ::Array
|
14
14
|
|
15
|
+
def select_first(&block)
|
16
|
+
selected = nil
|
17
|
+
each do |item|
|
18
|
+
selected = block.call(item)
|
19
|
+
break if selected
|
20
|
+
end
|
21
|
+
selected
|
22
|
+
end
|
23
|
+
|
15
24
|
def walk(obj)
|
16
25
|
path = self.dup
|
17
|
-
|
18
|
-
|
19
|
-
val =
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
path.clear
|
28
|
-
sub
|
29
|
-
end
|
30
|
-
elsif /^[\d,\+-\.]+$/.match(key)
|
31
|
-
selected = nil
|
32
|
-
key.split('|').each do |option|
|
33
|
-
locators = option.split(',').map do |dex|
|
34
|
-
range = /(?<start>\d+)(?:-|\+|\.\.(?<exclusive>\.)?)?(?<end>-?\d+)/.match(dex)
|
35
|
-
range ? Range.new(range['start'].to_i, (range['end'] || -1).to_i, range['exclusive']) : dex.to_i
|
36
|
-
end
|
37
|
-
selected = obj.values_at(*locators)
|
38
|
-
break if selected
|
39
|
-
end
|
40
|
-
selected.size == 1 ? selected.first : selected
|
41
|
-
end
|
42
|
-
elsif obj.is_a? Hash
|
43
|
-
match = key[/\/(.*)\//, 1]
|
44
|
-
if match.nil?
|
45
|
-
obj[key]
|
46
|
-
else
|
47
|
-
found = obj.keys.select { |k| Regexp.new(match).match(k) }
|
48
|
-
found = found.map { |k| path.empty? ? obj[k] : path.walk(obj[k]) }
|
49
|
-
path.clear
|
50
|
-
found = found.first if found.size < 2
|
51
|
-
found
|
26
|
+
keys = path.shift.to_s.split('|')
|
27
|
+
|
28
|
+
val = keys.select_first do |key|
|
29
|
+
if obj.is_a? Array
|
30
|
+
if key == '*'
|
31
|
+
if path.empty?
|
32
|
+
obj
|
33
|
+
else
|
34
|
+
sub = obj.map do |inner|
|
35
|
+
path.dup.walk(inner)
|
52
36
|
end
|
53
|
-
|
54
|
-
|
37
|
+
path.clear
|
38
|
+
sub
|
39
|
+
end
|
40
|
+
elsif /^[\d,\+-\.]+$/.match(key)
|
41
|
+
locators = key.split(',').map do |dex|
|
42
|
+
range = /(?<start>\d+)(?:-|\+|\.\.(?<exclusive>\.)?)?(?<end>-?\d+)/.match(dex)
|
43
|
+
range ? Range.new(range['start'].to_i, (range['end'] || -1).to_i, range['exclusive']) : dex.to_i
|
55
44
|
end
|
45
|
+
selected = obj.values_at(*locators)
|
46
|
+
selected.size == 1 ? selected.first : selected
|
47
|
+
end
|
48
|
+
elsif obj.is_a? Hash
|
49
|
+
match = key[/\/(.*)\//, 1]
|
50
|
+
if match.nil?
|
51
|
+
obj[key]
|
52
|
+
else
|
53
|
+
found = obj.keys.select { |k| Regexp.new(match).match(k) }
|
54
|
+
found = found.map { |k| path.empty? ? obj[k] : path.walk(obj[k]) }
|
55
|
+
path.clear
|
56
|
+
found = found.first if found.size < 2
|
57
|
+
found
|
58
|
+
end
|
59
|
+
elsif obj.respond_to? key
|
60
|
+
obj.send(key)
|
61
|
+
end
|
62
|
+
end
|
56
63
|
|
57
64
|
path.empty? ? val : path.walk(val)
|
58
65
|
end
|
@@ -103,65 +110,73 @@ module DJC
|
|
103
110
|
|
104
111
|
class Rule
|
105
112
|
def parse(paths)
|
106
|
-
|
107
113
|
regex = /\/[^\/]+\//
|
108
114
|
lookup = /\<[^\<]\>/
|
109
115
|
indexes = /(?:-?\d+(?:(?:\.\.\.?|-|\+)(?:-?\d+)?)?,?)+/
|
110
|
-
node = /[^\[\]\{\}
|
111
|
-
|
116
|
+
node = /[^\[\]\{\}\.]+/
|
117
|
+
paths.split('||').map do |path|
|
112
118
|
path.scan(/#{regex}|#{lookup}|#{indexes}|#{node}/)
|
113
119
|
end
|
114
120
|
|
115
|
-
rules
|
116
121
|
end
|
117
122
|
|
118
|
-
attr_reader :
|
119
|
-
def initialize(type
|
123
|
+
attr_reader :type, :paths, :blocks
|
124
|
+
def initialize(type, rules, &block)
|
120
125
|
if rules.is_a?(String) && rules[0] == '#'
|
121
|
-
@type, @
|
126
|
+
@type, @blocks, @paths = 'LITERAL', [proc { rules[1..-1] }], nil
|
122
127
|
else
|
123
|
-
@type, @
|
128
|
+
@type, @blocks, @paths = type, [block].compact, (rules.is_a?(String) ? parse(rules) : rules)
|
124
129
|
end
|
125
130
|
end
|
126
131
|
|
127
132
|
def to_s
|
128
|
-
|
133
|
+
rules = if type == 'LITERAL'
|
134
|
+
@blocks.first.call
|
135
|
+
elsif paths
|
136
|
+
paths.join(paths.first.is_a?(Rule) ? ' + ' : '.')
|
137
|
+
end
|
138
|
+
|
139
|
+
"#{type}(#{rules})"
|
129
140
|
end
|
130
141
|
|
131
142
|
def sum
|
132
|
-
@type
|
143
|
+
@type = 'SUM'
|
144
|
+
@blocks << proc { |array| array.map(&:to_i).inject(0, :+) if array }
|
133
145
|
self
|
134
146
|
end
|
135
147
|
|
136
148
|
def avg
|
137
|
-
@type
|
149
|
+
@type = 'AVG'
|
150
|
+
@blocks << proc { |array| ( array.map(&:to_i).inject(0.0, :+) / array.size) if array }
|
138
151
|
self
|
139
152
|
end
|
140
153
|
|
141
154
|
def each(&each_block)
|
142
|
-
@type
|
155
|
+
@type = 'EACH'
|
156
|
+
@blocks << proc { |array| array.map { |val| each_block.call(val) } if array }
|
143
157
|
self
|
144
158
|
end
|
145
159
|
|
146
160
|
def join(sep = '')
|
147
|
-
@type
|
161
|
+
@type = 'JOIN'
|
162
|
+
@blocks << proc { |vals| vals.is_a?(Array) ? vals.compact.join(sep) : vals }
|
148
163
|
self
|
149
164
|
end
|
150
165
|
|
151
166
|
def sort(&sort_block)
|
152
|
-
@type
|
167
|
+
@type = 'SORT'
|
168
|
+
@blocks << proc { |sort| sort.is_a?(Array) ? sort.compact.sort(&sort_block) : (sort.nil? ? nil : sort.sort(&sort_block)) }
|
153
169
|
self
|
154
170
|
end
|
155
171
|
|
156
172
|
def match(matcher)
|
157
|
-
@type
|
173
|
+
@type = 'MATCH'
|
174
|
+
@blocks << proc do |val|
|
158
175
|
if val
|
159
176
|
if val.is_a?(Array)
|
160
|
-
val.map do |v|
|
161
|
-
|
162
|
-
|
163
|
-
match.size == 1 ? match.first : match
|
164
|
-
end
|
177
|
+
val.compact.map do |v|
|
178
|
+
match = v.scan(matcher).flatten
|
179
|
+
match.size == 1 ? match.first : match
|
165
180
|
end
|
166
181
|
else
|
167
182
|
match = val.scan(matcher).flatten
|
@@ -173,17 +188,16 @@ module DJC
|
|
173
188
|
end
|
174
189
|
|
175
190
|
def apply(obj)
|
176
|
-
|
177
|
-
if type == 'lookup'
|
191
|
+
if @blocks.empty?
|
178
192
|
walker = paths.dup
|
179
193
|
value = nil
|
180
|
-
while value.nil? && path = walker.shift
|
181
|
-
value = path.walk(obj)
|
194
|
+
while value.nil? && (path = walker.shift)
|
195
|
+
value = path.is_a?(Rule) ? path.apply(obj) : path.walk(obj)
|
182
196
|
end
|
183
197
|
value
|
184
198
|
else
|
185
199
|
if paths.nil? || paths.empty?
|
186
|
-
value = block.call(
|
200
|
+
value = blocks.inject(obj) { |val, block| block.call(val) }
|
187
201
|
elsif paths.length > 1
|
188
202
|
value = [[]]
|
189
203
|
paths.each_with_index do |rule, index|
|
@@ -198,23 +212,22 @@ module DJC
|
|
198
212
|
value.first << val
|
199
213
|
end
|
200
214
|
end
|
201
|
-
value = value.map { |val| block.call(
|
215
|
+
value = value.map { |val| blocks.inject(val) { |v, block| block.call(v) }} unless blocks.empty?
|
202
216
|
value = value.first if value.length == 1
|
203
217
|
value
|
204
218
|
else
|
205
219
|
value = paths.first.apply(obj)
|
206
|
-
value = block.call(
|
220
|
+
value = blocks.inject(value) { |val, block| block.call(val) } unless blocks.empty?
|
207
221
|
end
|
208
222
|
end
|
209
223
|
value
|
210
224
|
end
|
211
|
-
|
212
225
|
end
|
213
226
|
|
214
227
|
class Column
|
215
228
|
attr_reader :name, :rule
|
216
229
|
def initialize(name, rule)
|
217
|
-
@name, @rule = name, rule.is_a?(Rule) ? rule : Rule.new(rule)
|
230
|
+
@name, @rule = name, rule.is_a?(Rule) ? rule : Rule.new('LOOKUP', rule)
|
218
231
|
end
|
219
232
|
end
|
220
233
|
|
@@ -226,7 +239,7 @@ module DJC
|
|
226
239
|
end
|
227
240
|
|
228
241
|
def initialize(path = nil)
|
229
|
-
@path = Rule.new(path) if path
|
242
|
+
@path = Rule.new('USING', path) if path
|
230
243
|
end
|
231
244
|
|
232
245
|
attr_reader :columns
|
@@ -252,11 +265,11 @@ module DJC
|
|
252
265
|
end
|
253
266
|
|
254
267
|
def with(*paths, &block)
|
255
|
-
Rule.new('
|
268
|
+
Rule.new('WITH', paths.map { |path| Rule.new('LOOKUP', path) }, &block)
|
256
269
|
end
|
257
270
|
|
258
271
|
def rule(&block)
|
259
|
-
Rule.new('
|
272
|
+
Rule.new('RULE', nil, &block)
|
260
273
|
end
|
261
274
|
|
262
275
|
def build(json)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: djc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|