Module: Arguments

Included in:
Class, Module
Defined in:
lib/arguments.rb,
lib/arguments/vm.rb,
lib/arguments/mri.rb,
lib/arguments/class.rb

Defined Under Namespace

Classes: PermissiveRubyParser

Constant Summary collapse

VERSION =
'0.6.1'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.ast_for_method(klass, method) ⇒ Object



15
16
17
18
19
20
# File 'lib/arguments/vm.rb', line 15

def self.ast_for_method klass, method
  source, line = klass.instance_method(method).source_location
  str = IO.readlines( source )[ (line-1)..-1 ].join
  ast = PermissiveRubyParser.new.parse( str )
  ast.assoc( :defn ) or ast
end

.names(klass, method) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/arguments.rb', line 12

def self.names klass, method
  args = ast_for_method(klass, method).assoc(:args)
  args = args[1..-1]
  
  return [] if args.empty? or args.last.is_a?(Symbol)
  vals = args.pop[1..-1]

  args.collect do |arg|
    if val = vals.find{ |v| v[1] == arg }
      [arg, Ruby2Ruby.new.process(val.last)]
    else
      [arg]
    end
  end
end

Instance Method Details

#named_arguments_for(*methods) ⇒ Object Also known as: named_args_for, named_args



2
3
4
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
# File 'lib/arguments/class.rb', line 2

def named_arguments_for *methods
  methods = instance_methods - Object.methods if methods.empty?
      
  methods.each do |meth|
    meth    = meth.to_s
    original_klass = self
    if meth =~ /^self\./
      am_self = true
      klass = (class << self; self; end)
      meth.sub!(/^self\./ , '')
    else
      klass = self
    end
    names   = Arguments.names klass, meth
    next if names.empty? or names.inject(false) { |bol, pair| bol || /^\*/ === pair.first.to_s }
    assigns = []
    names.pop if /^&/ === names[-1][0].to_s
    
    names.each_with_index do |name, index|
      unless name.size == 1
        assigns << <<-RUBY_EVAL
          #{ name.first } =
          if opts.key? :#{ name.first }
            opts.delete :#{ name.first }
          else
            args.size >= #{ index + 1 } ? args[#{ index }] : #{ name.last }
          end
        RUBY_EVAL
      else
        assigns << <<-RUBY_EVAL 
          begin
            #{ name.first } = opts.key?(:#{ name.first }) ? opts.delete(:#{ name.first }) : args.fetch(#{ index })
          rescue 
            raise ArgumentError.new('passing `#{ name.first }` is required')
          end
        RUBY_EVAL
      end
    end


    it = <<-RUBY_EVAL, __FILE__, __LINE__
      #{ "class << self" if am_self } 
      def __#{ meth }_with_keyword_arguments *args, &block
        opts = args.last.kind_of?( Hash ) && args.size < #{ names.size } ? args.pop : {}
        #{ assigns.join("\n") }
        unless opts.empty?
          raise ArgumentError.new("`\#{ opts.keys.join(', ') }` \#{ opts.size == 1 ? 'is not a recognized argument keyword' : 'are not recognized argument keywords' }") 
        end
        __original_#{ meth } #{ names.collect{ |n| n.first }.join(', ') }, &block
      end

      alias __original_#{ meth } #{ meth }
      alias #{ meth } __#{ meth }_with_keyword_arguments
      #{ "end" if am_self }
    RUBY_EVAL
    original_klass.class_eval *it
  end
end