class Object

Public Instance Methods

_destructure_set(name, value, binding, caller) click to toggle source
# File lib/destructure/destructure.rb, line 64
def _destructure_set(name, value, binding, caller)
  if name.is_a?(String) || binding.eval("defined? #{name}") == 'local-variable'
    $binding_temp = value
    binding.eval("#{name} = $binding_temp")
  else
    if binding.eval('self').respond_to?(name, true)
      raise "Cannot have pattern variable named '#{name}'. A method already exists with that name. Choose a different name, " +
                "or pre-initialize a local variable that shadows the method."
    end
    @_destructure_env ||= {}
    @_destructure_env[caller] ||= {}
    @_destructure_env[caller][name] = value
  end
end
all_field_patterns_match(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 47
def all_field_patterns_match(pat, x)
  all_match(pat.fields.keys.map { |name| x.respond_to?(name) && match(pat.fields[name], x.send(name)) })
end
all_match(xs) click to toggle source
# File lib/destructure/dmatch.rb, line 153
def all_match(xs)
  xs.all?{|x| x.is_a?(Env)}
end
dbind_internal(x, sexp, caller_binding, caller_location) click to toggle source
# File lib/destructure/destructure.rb, line 45
def dbind_internal(x, sexp, caller_binding, caller_location)
  env = dbind_no_ostruct_sexp(x, sexp, caller_binding)
  return nil if env.nil?

  if bind_locals
    env.keys.each {|k| _destructure_set(k.name, env[k], caller_binding, caller_location)}
  end

  ostruct_env = env.to_openstruct
  set_custom_env(ostruct_env) if self.respond_to?(:set_custom_env, true)
  ostruct_env
end
dbind_no_ostruct_sexp(x, sexp, caller_binding) click to toggle source
# File lib/destructure/destructure.rb, line 58
def dbind_no_ostruct_sexp(x, sexp, caller_binding)
  sp = sexp
  pat = SexpTransformer.transform(sp, caller_binding)
  DMatch::match(pat, x)
end
decompose_splatted_enumerable(pat) click to toggle source
# File lib/destructure/dmatch.rb, line 106
def decompose_splatted_enumerable(pat)
  before = []
  splat = nil
  after = []
  pat.each do |p|
    case
      when p.is_a?(Splat)
        if splat.nil?
          splat = p
        else
          raise "cannot have more than one splat in a single array: #{pat.inspect}"
        end
      when splat.nil?
        before.push(p)
      else
        after.push(p)
    end
  end

  splat && [before, splat, after]
end
enumerable(*xs) click to toggle source
# File lib/destructure/dmatch.rb, line 145
def enumerable(*xs)
  xs.all?{|x| x.is_a?(Enumerable)}
end
hash(*xs) click to toggle source
# File lib/destructure/dmatch.rb, line 149
def hash(*xs)
  xs.all?{|x| x.is_a?(Hash)}
end
len(x) click to toggle source
# File lib/destructure/dmatch.rb, line 137
def len(x)
  x.respond_to?(:length) ? x.length : x.count
end
match_enumerable(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 77
def match_enumerable(pat, x)
  case
    when (parts = decompose_splatted_enumerable(pat))
      pat_before, pat_splat, pat_after = parts
      x_before = x.take(pat_before.length)
      if pat_after.any?
        splat_len = len(x) - pat_before.length - pat_after.length
        return nil if splat_len < 0
        x_splat = x.drop(pat_before.length).take(splat_len)
      else
        x_splat = x.drop(pat_before.length)
      end

      before_and_splat_result = match_enumerable_no_splats(pat_before, x_before) && match(pat_splat, x_splat)

      if before_and_splat_result && pat_after.any?
        # do this only if we have to, since it requires access to the end of the enumerable,
        # which doesn't work with infinite enumerables
        x_after = take_last(pat_after.length, x)
        match_enumerable_no_splats(pat_after, x_after)
      else
        before_and_splat_result
      end
    when len(pat) == len(x)
      match_enumerable_no_splats(pat, x)
    else; nil
  end
end
match_enumerable_no_splats(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 141
def match_enumerable_no_splats(pat, x)
  all_match(pat.zip(x).map{|a| match(*a)}) ? @env : nil
end
match_filter_splat(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 73
def match_filter_splat(pat, x)
  @env.bind(pat, x.map { |z| [z, match(pat.pattern, z)] }.reject { |q| q.last.nil? }.map { |q| q.first })
end
match_or(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 55
def match_or(pat, x)
  pat.patterns.lazy.map{|p| match(p, x)}.reject{|e| e.nil?}.first
end
match_regexp(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 42
def match_regexp(pat, x)
  m = pat.match(x)
  m && @env.merge!(Hash[pat.named_captures.keys.map { |k| [Var.new(k.to_sym), m[k]] }])
end
match_select_splat(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 63
def match_select_splat(pat, x)
  x_match_and_env = x.map { |z| [z, DMatch::match(pat.pattern, z)] }.reject { |q| q.last.nil? }.first
  if x_match_and_env
    x_match, env = x_match_and_env
    @env.bind(pat, x_match) && @env.merge!(env)
  else
    nil
  end
end
match_splat(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 59
def match_splat(pat, x)
  @env.bind(pat, enumerable(x) ? x : [x])
end
match_var(pat, x) click to toggle source
# File lib/destructure/dmatch.rb, line 51
def match_var(pat, x)
  @env.bind(pat, x)
end
method_missing(name, *args, &block) click to toggle source
Calls superclass method
# File lib/destructure/destructure.rb, line 79
def method_missing(name, *args, &block)
  if bind_locals
    c = caller_locations(1,1)[0].label
    @_destructure_env ||= {}
    caller_hash = @_destructure_env[c]
    caller_hash && caller_hash.keys.include?(name) ? caller_hash[name] : super
  else
    super
  end
end
take_last(n, xs) click to toggle source
# File lib/destructure/dmatch.rb, line 128
def take_last(n, xs)
  result = []
  xs.reverse_each do |x|
    break if result.length == n
    result.unshift x
  end
  result
end