Module: Cube::Trait

Defined in:
lib/cube/traits.rb

Defined Under Namespace

Classes: IncludeError, MethodConflict

Instance Method Summary collapse

Instance Method Details

#append_features(mod) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/cube/traits.rb', line 16

def append_features(mod)
  if mod.is_a?(Class) && !mod.is_a?(CubeMethods)
    raise IncludeError, "Traits can only be mixed into cube classes"
  end
  unless mod.instance_variable_defined?(:@__trait_allow_include) &&
    mod.instance_variable_get(:@__trait_allow_include)
    raise IncludeError, "Traits can only be mixed in using method `with_trait`"
  end
  conflicts = public_instance_methods & mod.public_instance_methods
  errors = conflicts.map { |c|
    meth = mod.instance_method(c)
    { meth: meth, owner: meth.owner } unless meth.owner.is_a?(Class)
  }.compact
  unless errors.empty?
    message = "\n" + errors.map { |e| e[:meth].to_s }.join("\n")
    raise MethodConflict, message
  end
  if @__interface_trait_required_interface && mod.is_a?(Class)
    intf = @__interface_trait_required_interface
    mod.include?(intf) || mod.as_interface(intf, runtime_checks: false)
  end
  super
end

#assert_match(intf) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/cube/traits.rb', line 55

def assert_match(intf)
  self_methods = instance_methods
  inherited = self.ancestors.select{ |x| Trait === x }
  required_interface_spec = inherited.inject({}) { |acc, x|
    req = x.instance_variable_get('@__interface_trait_required_interface')
    if req
      acc.merge(req.to_spec)
    else
      acc
    end
  }
  self_methods.each do |sm|
    required_interface_spec.delete(sm)
  end
  Interface.match_specs(required_interface_spec, intf.to_spec)
end

#requires_interface(intf) ⇒ Object



9
10
11
12
13
14
# File 'lib/cube/traits.rb', line 9

def requires_interface(intf)
  unless intf.is_a? Cube::Interface
    raise ArgumentError, "#{intf} is not a Cube::Interface"
  end
  @__interface_trait_required_interface = intf
end

#wrap(intf) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/cube/traits.rb', line 40

def wrap(intf)
  assert_match(intf)
  cls = Class.new(SimpleDelegator) do
    define_method(:initialize) do |obj|
      $stderr.puts "Checking with #{intf}"
      Cube.check_type(intf, obj)
      super(obj)
    end
  end
  inc_trait = clone
  inc_trait.instance_variable_set(:@__interface_trait_required_interface, nil)
  inc_trait.instance_variable_set(:@__trait_cloned_from, self)
  Cube[cls].with_trait(inc_trait)
end