Class: Object

Inherits:
BasicObject
Defined in:
lib/ex/defmodule.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.const_missing(name) ⇒ Object



64
65
66
# File 'lib/ex/defmodule.rb', line 64

def self.const_missing(name)
  name
end

Instance Method Details

#defmodule(name, &block) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/ex/defmodule.rb', line 5

def defmodule(name, &block)
  eval("#{name.to_s} = Module.new()")

  m = Kernel.const_get(name.to_s)

  m.class_eval do
    def method_missing(m_missing_name, *m_missing_args, &m_missing_block)
      [m_missing_name, m_missing_args, m_missing_block]
    end

    module_function :method_missing
  end

  m.class_variable_set(:@@public_functions, {})
  m.class_variable_set(:@@current_arg_values, [])
  m.class_variable_set(:@@current_arg_names, [])

  m.class_eval do
    def defP(ast, &block)
      function_name = ast[0]
      arg_names = ast[1].map {|list| list[0]}
      arity = arg_names.size

      p = self.class_variable_get(:@@public_functions)
      p[{name: function_name, arity: arity}] = {args: arg_names, proc: block}
      p = self.class_variable_set(:@@public_functions, p)
    end

    m.class_eval do
      def method_missing(m_missing_name, *m_missing_args, &m_missing_block)

        if f = self.class_variable_get(:@@public_functions)[{name: m_missing_name, arity: m_missing_args.size}]
          self.class_variable_set(:@@current_arg_values, m_missing_args)
          self.class_variable_set(:@@current_arg_names, f[:args])

          f[:proc].call
        elsif index = self.class_variable_get(:@@current_arg_names).find_index(m_missing_name)
          self.class_variable_get(:@@current_arg_values)[index]
        else
          raise UndefinedFunctionError
        end
      end
    end

    alias_method :dẹf, :defP

    module_function :defP, :dẹf
  end

  m.class_eval(&block)

  eval("
    module #{m}
      module_function #{m.instance_methods.map(&:to_s).map {|t| ':' + t }.join(', ')}
    end
  ")

end