Class: Module

Inherits:
Object show all
Defined in:
lib/carat/attr.rb,
lib/carat/macro.rb,
lib/carat-dev/vars/vars.rb,
lib/carat-dev/vars/vars.rb,
lib/carat-dev/interface_work/type.rb,
lib/carat-dev/access-blocks/access_blocks.rb,
lib/carat-dev/interface_work/SCRAP/interface.rb,
lib/carat-dev/interface_work/SCRAP/i-contracts.rb,
lib/carat-dev/import-module/import-module-0.81/lib/import-module.rb,
lib/carat-dev/interface_work/contracts/contract/lib/contract/integration.rb,
lib/carat-dev/interface_work/SCRAP/j-interface/interface-0.1.0/lib/interface.rb

Overview

Ruby Treasures 0.4 Copyright © 2002 Paul Brannan <[email protected]>

You may distribute this software under the same terms as Ruby (see the file COPYING that was distributed with this library).

A hack to allow a mixin to be used like Java’s “interfaces”.

E.g.: <pre>

module Foo
  interface_method :foo
  interface_method :bar
end

class XYZ
  def bar
  end
end

class Bar < XYZ
  include Foo
  def foo
    puts "foo"
  end
end

b = Bar.new
assert_object_includes_complete(b, Foo)

</pre>

Constant Summary collapse

PVars =
{}
PUBLIC =
0
PROTECTED =
1
PRIVATE =
2
SECRET =
3

Instance Method Summary collapse

Instance Method Details

#alias_method(a, b) ⇒ Object



435
436
437
438
439
440
# File 'lib/carat-dev/import-module/import-module-0.81/lib/import-module.rb', line 435

def alias_method(a, b)
  a0 = a.sub(/__IMPORT_MODULE_PREFIX_/, "@").sub(/\d+(\d{3})/, '\1')
  b0 = b.sub(/__IMPORT_MODULE_PREFIX_/, "@").sub(/\d+(\d{3})/, '\1')
  puts "#{self}> #{a0} = #{b0}"
  alias_method_orig a, b
end

#alias_method_origObject



434
# File 'lib/carat-dev/import-module/import-module-0.81/lib/import-module.rb', line 434

alias alias_method_orig alias_method

#append_dynamic_features(base, options) ⇒ Object

Note: Is this the best name for this callback?



45
46
47
48
49
# File 'lib/carat/macro.rb', line 45

def append_dynamic_features( base, options )
  macros.each do |m|
    base.class_eval m.call( options )
  end
end

#attr(*args) ⇒ Object

The wondrful shortcut.



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/carat/attr.rb', line 293

def attr(*args)
  # Allows compatibility with old definition, while also
  # extending the capabilites to allow multiple parameters.
  # This form does not allow casting though.
  if TrueClass === args.last or FalseClass === args.last or NilClass === args.last
    if args.pop
      args.concat( args.collect{ |a|
        a = a.to_s.strip
        case a[-1,1]
        when '=' 
          a[0..-2]
        when '?' 
          "#{a[0..-2]}="
        else
          "#{a}="
        end
      } )
    end
  end
  #
  made = []
  readers = []
  writers = []
  testers = []
  if Hash === args.last
    args.concat( args.pop.to_a )
  end
  args.each do |a,c|
    a = a.to_s.strip
    t = a.slice(-1,1)
    m = a.chomp('!').chomp('=').chomp('?')
    case t
    when '='
      readers << [m,c]
      writers << [m,c]
    when '?'
      testers << [m,c]
    when '!'
      writers << [m,c]
    else
      readers << [m,c]
    end
  end
  made.concat( [ attr_reader( *readers ) ] )
  made.concat( [ attr_writer( *writers ) ] )
  made.concat( [ attr_tester( *testers ) ] )
  return *made
end

#attr_accessor(*args) ⇒ Object

Create an attribute method for writing to an instance variable. This is the same as the built in method, which it replaces, but adds casting.

Casting allows the addition of a method invocation on the instance variable. It is defined using a hash parameter, so all castings must come at the end of a call to attr_writer.

require 'carat/attr'

attr_accessor :a => :to_s

_is equivalent to_

def a
  @a.to_s
end

def a=(x)
  @a = x.to_s
end


183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/carat/attr.rb', line 183

def attr_accessor(*args)
  made = []
  if Hash === args.last
    args.concat( args.pop.to_a )
  end
  #hargs = (Hash === args.last ? args.pop : {})
  args.each { |a,c|
    a = a.to_s.strip.chomp('=')
    c = ".#{c.to_s.strip}".chomp('.')
    module_eval %Q{ def #{a}; @#{a}#{c} ; end }
    module_eval %Q{ def #{a}=(x); @#{a}=x#{c}; end }
    made << "#{a}".to_sym
    made << "#{a}=".to_sym
  }
  (@__atributes__ ||= []).concat( made )
  return *made
end

#attr_reader(*args) ⇒ Object

Create an attribute method for reading an instance variable. This is the same as the built in method, which it replaces, but adds casting.

Casting allows the addition of a method invocation on the instance variable. It is defined using a hash parameter, so all castings must come at the end of a call to attr_reader.

require 'carat/attr'

attr_reader :a => :to_s

_is equivalent to_

def a
  @a.to_s
end


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/carat/attr.rb', line 109

def attr_reader(*args)
  made = []
  if Hash === args.last
    args.concat( args.pop.to_a )
  end
  #hargs = (Hash === args.last ? args.pop : {})
  args.each { |a,c|
    a = a.to_s.strip
    c = ".#{c.to_s.strip}".chomp('.')
    module_eval %Q{ def #{a}; @#{a}#{c} ; end }
    made << "#{a}".to_sym
  }
  (@__atributes__ ||= []).concat( made )
  return *made
end

#attr_setter(*args) ⇒ Object

Create an attribute method for getting and setting an instance variable.

require 'carat/attr'

attr_setter :a

_is equivalent to_

def a(*args)
  if args.size > 0
    @a = args[0]
    self
  else
    @a
  end
end

Casting is supported on both getting and setting.

attr_setter :a => :to_s

_is equivalent to_

def a(*args)
  @a = args[0].to_s if args.size > 0
  @a.to_s
end


269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/carat/attr.rb', line 269

def attr_setter(*args)
  made = []
  if Hash === args.last
    args.concat( args.pop.to_a )
  end
  #hargs = (Hash === args.last ? args.pop : {})
  args.each { |a,c|
    a = a.to_s.strip
    c = ".#{c.to_s.strip}".chomp('.')
    module_eval %Q{
      def #{a}(*args)
        args.size > 0 ? ( @#{a}=args[0]#{c} ; self ) : @#{a}#{c}
      end
    }
    made << "#{a}".to_sym
  }
  (@__atributes__ ||= []).concat( made )
  return *made
end

#attr_tester(*args) ⇒ Object

Create an attribute method for boolean testing of an instance variable in the form of var?.

require 'facet/module/attr_tester'

attr_tester :a

_is equivalent to_

def a?
  @a ? true : @a
end

Casting is also supported (see attr_reader).

attr_tester :a => :evaluate

_is equivalent to_

def a?
  @a.evaluate ? true : @a
end


224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/carat/attr.rb', line 224

def attr_tester(*args)
  made = []
  if Hash === args.last
    args.concat( args.pop.to_a )
  end
  #hargs = (Hash === args.last ? args.pop : {})
  args.each { |a,c|
    a = a.to_s.strip.chomp('?')
    c = ".#{c.to_s.strip}".chomp('.')
    module_eval %Q{ def #{a}?; @#{a}#{c} ? true : @#{a}#{c}; end }
    made << "#{a}?".to_sym
  }
  (@__atributes__ ||= []).concat made
  return *made
end

#attr_writer(*args) ⇒ Object

Create an attribute method for writing to an instance variable. This is the same as the built in method, which it replaces, but adds casting.

Casting allows the addition of a method invocation on the instance variable. It is defined using a hash parameter, so all castings must come at the end of a call to attr_writer.

require 'carat/attr'

attr_writer :a => :to_s

_is equivalent to_

def a=(x)
  @a = x.to_s
end


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/carat/attr.rb', line 144

def attr_writer(*args)
  made = []
  if Hash === args.last
    args.concat( args.pop.to_a )
  end
  #hargs = (Hash === args.last ? args.pop : {})
  args.each { |a,c|
    a = a.to_s.strip.chomp('=').chomp('!')
    c = ".#{c.to_s.strip}".chomp('.')
    module_eval %Q{ def #{a}=(x); @#{a}=x#{c}; end }
    made << "#{a}=".to_sym
  }
  (@__atributes__ ||= []).concat( made )
  return *made
end

#extend(*args) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/carat/macro.rb', line 53

def extend(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  for mod in args
    mod.extend_dynamic_object( self, options )
  end
  extend_without_macros(*args)
end

#extend_dynamic_object(base, options) ⇒ Object

Note: Is this the best name for this callback?



62
63
64
65
66
# File 'lib/carat/macro.rb', line 62

def extend_dynamic_object( base, options )
  macros.each do |m|
    (class << base; self ; end).class_eval m.call( options )
  end
end

#extend_without_macrosObject



51
# File 'lib/carat/macro.rb', line 51

alias_method :extend_without_macros, :extend

#implements(m) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/carat-dev/interface_work/SCRAP/i-contracts.rb', line 11

def implements(*klasses)
  klasses.each do |klass|
    unless klass === Class
      InterfaceContracts.module_eval %Q{
        class ::InterfaceContracts::#{klass} < ::#{klass}; end
        #{klass}.freeze
      }
    end
  end
  ifc_str = '[' + klasses.collect { |k| "InterfaceContracts::#{k.name}" }.join(',') + ']'
  ifm = Module.new
  ifm.module_eval %Q{
    def initialize(*args)
      #{ifc_str}.each do |k|
        umeths = k.public_instance_methods(true) - self.public_methods
        if umeths != []
          raise ImplementationError, self.class.name + " as "  + k.name + "\n" + umeths.sort.join(', ')
        end
      end
      super
    end
  }
  class_eval { include ifm }
end

#include(mod) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/carat/macro.rb', line 36

def include(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  for mod in args
    mod.append_dynamic_features( self, options )
  end
  include_without_macros(*args)
end

#include_origObject



428
429
430
431
432
433
434
# File 'lib/carat-dev/import-module/import-module-0.81/lib/import-module.rb', line 428

def include(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  for mod in args
    mod.append_dynamic_features( self, options )
  end
  include_without_macros(*args)
end

#include_without_macrosObject



34
# File 'lib/carat/macro.rb', line 34

alias_method :include_without_macros, :include

#includes_module?(mod) ⇒ Boolean

Determine if a class includes a module, in O(n) time.

Returns:

  • (Boolean)

    true if the class includes the module, false otherwise.



40
41
42
# File 'lib/carat-dev/interface_work/SCRAP/interface.rb', line 40

def includes_module?(mod)
  return included_modules.index(mod)
end

#macro(&blk) ⇒ Object



28
29
30
# File 'lib/carat/macro.rb', line 28

def macro( &blk )
  (@macros ||= []) << blk
end

#macrosObject



32
# File 'lib/carat/macro.rb', line 32

def macros ; @macros ||= [] ; end

#private(*args, &block) ⇒ Object



37
38
39
40
41
# File 'lib/carat-dev/access-blocks/access_blocks.rb', line 37

def private(*args, &block)
  __old_access_blocks_private__(args)
  block.call
  __old_access_blocks_private__(args)
end

#remove_method(a) ⇒ Object



443
444
445
446
447
# File 'lib/carat-dev/import-module/import-module-0.81/lib/import-module.rb', line 443

def remove_method(a)
  a0 = a.sub(/__IMPORT_MODULE_PREFIX_/, "@").sub(/\d+(\d{3})/, '\1')
  puts "#{self}> remove #{a0}"
  remove_method_orig a
end

#remove_method_origObject



442
# File 'lib/carat-dev/import-module/import-module-0.81/lib/import-module.rb', line 442

alias remove_method_orig remove_method

#signature(method, *args) ⇒ Object

Checks that the arguments and return value of a method match the specified signature.

Usage:

signature(:to_s) # no arguments
signature(:+, :any) # one argument, type unchecked
signature(:+, Fixnum) # one argument, type Fixnum
signature(:+, NumericContract)
signature(:+, 1 .. 10)

signature(:each, :block => true) # has to have block
signature(:to_i, :block => false) # not allowd to have block
signature(:to_i, :result => Fixnum) # return value must be Fixnum
signature(:zip, :allow_trailing => true) # unchecked trailing args
signature(:zip, :repeated => [Enumerable]) # repeated trailing args


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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/carat-dev/interface_work/contracts/contract/lib/contract/integration.rb', line 35

def signature(method, *args)
  return unless Contract.check_signatures?

  options = {}
  signature = args.dup
  options.update(signature.pop) if signature.last.is_a?(Hash)

  old_method = instance_method(method)
  remove_method(method)

  if old_method.arity < signature.size then
    raise(ArgumentError, "signature isn't compatible with arity")
  end

  if options.include?(:repeated)
    if options[:repeated].size == 0 then
      raise(ArgumentError, "repeated arguments may not be an empty Array")
    end
  end

  # We need to keep around references to our arguments because we will
  # need to access them via ObjectSpace._id2ref so that they do not
  # get garbage collected.
  @signatures ||= Hash.new
  @signatures[method] = args + [method]

  # We have to use class_eval so that signatures can be specified for
  # methods taking blocks in Ruby 1.8. (This will be obsolete in 1.9)
  # We also make the checks as efficient as we can.
  class_eval %{
    def #{method}(*args, &block)
      old_args = args.dup

      #{if options.include?(:block) then
          if options[:block] then
            %{raise(ArgumentError, "no block given") unless block}
          else
            %{raise(ArgumentError, "block given") if block}
          end
        end
      }

      #{unless options[:allow_trailing] or options.include?(:repeated)
          msg = "wrong number of arguments (\#{args.size} for " +
            "#{signature.size})"
          %{if args.size != #{signature.size} then
              raise(ArgumentError, "#{msg}")
            end
          }
        else
          msg = "wrong number of arguments (\#{args.size} for " +
            "at least #{signature.size}"
          %{if args.size < #{signature.size} then
              raise(ArgumentError, "#{msg}")
            end
          }
        end
      }

      #{index = 0
        signature.map do |part|
          next if part == :any
          index += 1
          msg = "argument #{index} (\#{arg.inspect}) does not match " +
            "#{part.inspect}"
          %{unless ObjectSpace._id2ref(#{part.object_id}) === (arg = args.shift)
              raise(ArgumentError, "#{msg}")
            end
          }
        end
      }

      #{if repeated = options[:repeated] then %{
          %{args.each_with_index do |arg, index|
              part = ObjectSpace._id2ref(#{repeated.object_id})
              if part != :any and not part[index % #{repeated.size}] === arg
                raise(ArgumentError, "argument \#{index + #{signature.size}}" +
                  "(\#{arg.inspect}) does not match \#{part.inspect}")
              end
            end
          }
        } end
      }

      result = ObjectSpace._id2ref(#{old_method.object_id}).bind(self).
        call(*old_args, &block)
      #{if rt = options[:return] and rt != :any then
          msg = "return value (\#{result.inspect}) does not match #{rt.inspect}"
          %{unless ObjectSpace._id2ref(#{rt.object_id}) === rt
              raise(StandardError, "#{msg}")
            end
          }
        end
      }
    end
  }, "(signature check for #{old_method.inspect[/: (.+?)>\Z/, 1]})"
end

#type(name, responders, &validator) ⇒ Object



200
201
202
203
204
205
206
207
208
# File 'lib/carat-dev/interface_work/type.rb', line 200

def type(name, responders, &validator)
  Type.new(name, responders, &validator)
  define_method(name) { |*vars|
    if $typecheck
      vars.all? { |v| Type[name].check(v) }
      return *vars
    end
  }
end

#undef_method(a) ⇒ Object



450
451
452
453
454
# File 'lib/carat-dev/import-module/import-module-0.81/lib/import-module.rb', line 450

def undef_method(a)
  a0 = a.sub(/__IMPORT_MODULE_PREFIX_/, "@").sub(/\d+(\d{3})/, '\1')
  puts "#{self}> undef #{a0}"
  undef_method_orig a
end

#undef_method_origObject



449
# File 'lib/carat-dev/import-module/import-module-0.81/lib/import-module.rb', line 449

alias undef_method_orig undef_method

#var(*vars) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/carat-dev/vars/vars.rb', line 15

def var(*vars)
  vars.flatten.each do |v|
    s = v.to_s
    case s[-1..-1]
    when '='
      s = s[0..-2]
      class_eval <<-EOS
        def #{s}=(arg)
          iv[:#{s}] = arg
          iv[:#{s}]
        end
      EOS
    else
      class_eval <<-EOS
        def #{v}(*args)
          iv[:#{v}] = args[0] if !args.empty?
          iv[:#{v}]
        end
      EOS
    end
  end
  return *vars
end