Class: DJC::DSL

Inherits:
Object
  • Object
show all
Defined in:
lib/djc.rb

Instance Method Summary collapse

Constructor Details

#initialize(rule = nil, parent = nil, name = parent.attempt(rule).__djc_build_name(rule), &block) ⇒ DSL

Returns a new instance of DSL.



178
179
180
181
182
183
184
185
# File 'lib/djc.rb', line 178

def initialize(rule = nil, parent = nil, name = parent.attempt(rule).__djc_build_name(rule), &block)
  @rule, @parent, @name, @capture, @finder, @nodes, @composer, @splatter, @partials = rule, parent, name, false, false, [], [], false, {}
  ctx(:djc_dsl_def) do
    ctx[:dsl] = self
    instance_eval(&block)
  end if block
  self
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



334
335
336
# File 'lib/djc.rb', line 334

def method_missing(name, *args, &block)
  __djc_dsl(name, *args, &block)
end

Instance Method Details

#*Object



286
287
288
289
# File 'lib/djc.rb', line 286

def *(*)
  @splatter = true
  self
end

#+@Object



190
191
192
193
194
# File 'lib/djc.rb', line 190

def +@()
  @capture = true
  @rule = @rule.gsub(/^\/([^()]*)\/$/, '/(\1)/') if @finder
  self
end

#>(other) ⇒ Object Also known as: %



195
196
197
198
# File 'lib/djc.rb', line 195

def >(other)
  @name = other
  self
end

#__djc_build_name(rule = nil) ⇒ Object



175
# File 'lib/djc.rb', line 175

def __djc_build_name(rule = nil) @name ? "#{@name}_#{rule}" : rule end

#__djc_dsl(name, *args, &block) ⇒ Object



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/djc.rb', line 315

def __djc_dsl(name, *args, &block)
  if name.to_s[0] == '_'
    if block
      @partials[name] = block
      self
    else
      partial = __djc_partial(name)
      dsl = instance_exec(*args, &partial)
      dsl.__djc_reparent(self)
      @nodes << dsl
      dsl
    end
  else
    dsl = DSL.new(name, self, *args, &block)
    @nodes << dsl
    dsl
  end
end

#__djc_partial(name) ⇒ Object



311
312
313
# File 'lib/djc.rb', line 311

def __djc_partial(name)
  @partials[name] || @parent.__djc_partial(name)
end

#__djc_reparent(parent) ⇒ Object



176
# File 'lib/djc.rb', line 176

def __djc_reparent(parent) @parent = parent end

#avg(*args, &block) ⇒ Object



249
250
251
252
253
254
255
256
# File 'lib/djc.rb', line 249

def avg(*args, &block)
  if ctx[:dsl] == self
    __djc_dsl(:avg, *args, &block)
  else
    compose { |*values| (values.map(&:to_f).inject(0.0, :+) / values.size) if values }
    self
  end
end

#capture(regex = nil, *captures, &block) ⇒ Object



291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/djc.rb', line 291

def capture(regex = nil, *captures, &block)
  if ctx[:dsl] == self
    args = [regex, *captures].compact
    __djc_dsl(:capture, *args, &block)
  else
    compose do |value|
      if (match = regex.match(value.to_s))
        if captures.empty?
          block ? block.call(match) : match.captures
        else
          symbols = captures.any? { |i| i.is_a?(String) || i.is_a?(Symbol) }
          captured = symbols ? captures.map { |name| match[name] } : match.to_a.values_at(*captures)
          block ? block.call(*captured) : captured
        end.sequester
      end
    end
    self
  end
end

#compose(*args, &block) ⇒ Object



220
221
222
223
224
225
226
227
# File 'lib/djc.rb', line 220

def compose(*args, &block)
  if ctx[:dsl] == self
    __djc_dsl(:compose, *args, &block)
  else
    @composer << block
    self
  end
end

#count(compact = false, &block) ⇒ Object



276
277
278
279
280
281
282
283
284
# File 'lib/djc.rb', line 276

def count(compact = false, &block)
  if ctx[:dsl] == self
    args = compact ? [compact] : []
    __djc_dsl(:count, *args, &block)
  else
    compose { |*values| compact ? values.compact.size : values.size }
    self
  end
end

#emit_name(name = nil) ⇒ Object



166
167
168
169
170
171
172
173
174
# File 'lib/djc.rb', line 166

def emit_name(name = nil)
  if @name.is_a?(Proc)
    @name.call(name)
  elsif @finder && name
    name
  else
    "#@name#{ "_#{name}" if name }"
  end
end

#find(rule, &block) ⇒ Object Also known as: match, with, field



212
213
214
215
# File 'lib/djc.rb', line 212

def find(rule, &block)
  rule = rule.inspect if rule.is_a?(Regexp)
  ~__djc_dsl(rule, &block)
end

#join(delimiter = $,, &block) ⇒ Object



229
230
231
232
233
234
235
236
237
# File 'lib/djc.rb', line 229

def join(delimiter=$,, &block)
  if ctx[:dsl] == self
    args = delimiter != $, ? [delimiter] : []
    __djc_dsl(:join, *args, &block)
  else
    compose { |*values| [*values].join(delimiter) }
    self
  end
end

#parse(data, extract = true) ⇒ Object



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/djc.rb', line 358

def parse(data, extract = true)
  if @capture
    rule_parse(data)
  else
    data = if @finder && extract
      @rule.to_s.walk(data)
    elsif data && @rule && extract && data.is_a?(Hash)
      data[@rule]
    else
      data
    end
    if data.is_a?(Array)
      data.flat_map do |element|
        parse(element, false)
      end
    else
      @nodes.inject([]) do |rows, node|
        result = node.parse(data)
        result.flat_map do |res|
          rows.empty? ? res : rows.map { |row| row.merge(res) }
        end
      end
    end
  end
end

#rule_parse(data) ⇒ Object



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# File 'lib/djc.rb', line 338

def rule_parse(data)
  if data.is_a?(Array)
    data.flat_map do |element|
      rule_parse(element)
    end
  else
    values = @rule.to_s.walk(data)

    row = if (@splatter || @finder) && values.is_a?(Hash)
      values.each.with_object({}) { |(k, v), r| r[emit_name(k)] = v }
    elsif @splatter && values.is_a?(Array)
      values.each.with_index.with_object({}) { |(v, i), r| r[emit_name(i)] = v }
    else
      { emit_name => values }
    end

    [ @composer.empty? ? row : row.each.with_object({}) { |(k,v), r| r[k] = @composer.inject(v) { |m,c| c.call(*m) } } ]
  end
end

#sort(*args, &block) ⇒ Object



258
259
260
261
262
263
264
265
# File 'lib/djc.rb', line 258

def sort(*args, &block)
  if ctx[:dsl] == self
    __djc_dsl(:sort, *args, &block)
  else
    compose { |*sort| sort.compact.sort(&block) }
    self
  end
end

#sum(initial = 0.0, op = :+, &block) ⇒ Object



239
240
241
242
243
244
245
246
247
# File 'lib/djc.rb', line 239

def sum(initial = 0.0, op = :+, &block)
  if ctx[:dsl] == self
    args = initial != 0.0 ? [initial] : []
    __djc_dsl(:sum, *args, &block)
  else
    compose { |*values| values.map(&:to_f).inject(initial, block ? block : op) if values }
    self
  end
end

#to_s(depth = 0) ⇒ Object



202
203
204
205
206
207
208
209
210
# File 'lib/djc.rb', line 202

def to_s(depth = 0)
  str = "DJC:"
  str += @capture ? "+" : ""
  str += (@rule || "ROOT").to_s
  str += "(#@name)" if @name
  str += " [#{@partials.keys.join(",")}]" unless @partials.empty?
  str += " {\n#{@nodes.map {|n| ("  " * (depth + 1)) + n.to_s(depth + 1)}.join("\n") }\n#{"  " * depth}}" unless @nodes.empty?
  str
end

#to_strObject



201
# File 'lib/djc.rb', line 201

def to_str() to_s end

#uniq(*args, &block) ⇒ Object



267
268
269
270
271
272
273
274
# File 'lib/djc.rb', line 267

def uniq(*args, &block)
  if ctx[:dsl] == self
    __djc_dsl(:uniq, *args, &block)
  else
    compose { |*values| values.uniq }
    self
  end
end

#~@Object



186
187
188
189
# File 'lib/djc.rb', line 186

def ~@()
  @finder = true
  self
end