Quick actions

cmd+k|ctrl+k

Navigation

Languages

not real ViewFromTo

Snippet info

Language

Ruby

Visibility

public

Author

hyrious

Created

2019-03-09T16:33:56Z

Updated

2019-03-09T16:49:28Z

module ViewFromTo
  KLASSES = []
  RULES = []
  def self.extended(klass)
    KLASSES << klass
    RULES.each do |a, o, b, l|
      if klass.to_s == a || a == '*'
        m = klass.instance_method(o) if o != :method_missing and klass.method_defined?(o) # should exist better way
        klass.define_method(o) do |*args, &blk|
          m.bind(self).call(*args, &blk) if m
          l.call(self, *args, &blk) if args[o == :method_missing ? 1 : 0].kind_of?(b) # should exist better way
        end
      end
    end
  end
  
  def def_from pattern='*', meth=:method_missing, &blk
    RULES << [pattern, meth, self, blk]
  end

  def def_to pattern='*', meth=:method_missing, &blk
    klass = pattern == '*' ? Object : KLASSES.find { |k| k.to_s == pattern }
    define_method meth do |*args|
      self.instance_exec(*args, &blk) if args[meth == :method_missing ? 1 : 0].kind_of?(klass) # should exist better way
    end
  end
end

# the better way:
# 1. add full type check, see https://glot.io/snippets/f48os6pmhy
# 2. better wrap method_missing, this one is a fake one

class Apple
  extend ViewFromTo
  
  def_from '*' do # *.*(apple)
    puts "i'm just an apple"
  end
  
  def_from 'Human', :taste do |human| # human.taste(apple)
    puts "i'm taste #{human.age < 1 ? 'juicy' : 'odd'}"
  end
end

class Human
  extend ViewFromTo

  attr_accessor :age
  def initialize(age) @age = age end
  
  def_to 'Apple', :taste do |apple| # human.taste(apple) # override previous one
    puts age < 1 ? 'juicy' : 'cannot eat'
  end
end

class OtherThing
  extend ViewFromTo
end

Human.new(0).taste(Apple.new) # juicy
Human.new(2).taste(Apple.new) # cannot eat
OtherThing.new.taste(Apple.new) # i'm just an apple
INFO