Class: Module
- 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
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
- #alias_method(a, b) ⇒ Object
- #alias_method_orig ⇒ Object
-
#append_dynamic_features(base, options) ⇒ Object
Note: Is this the best name for this callback?.
-
#attr(*args) ⇒ Object
The wondrful shortcut.
-
#attr_accessor(*args) ⇒ Object
Create an attribute method for writing to an instance variable.
-
#attr_reader(*args) ⇒ Object
Create an attribute method for reading an instance variable.
-
#attr_setter(*args) ⇒ Object
Create an attribute method for getting and setting an instance variable.
-
#attr_tester(*args) ⇒ Object
Create an attribute method for boolean testing of an instance variable in the form of var?.
-
#attr_writer(*args) ⇒ Object
Create an attribute method for writing to an instance variable.
- #extend(*args) ⇒ Object
-
#extend_dynamic_object(base, options) ⇒ Object
Note: Is this the best name for this callback?.
- #extend_without_macros ⇒ Object
- #implements(m) ⇒ Object
- #include(mod) ⇒ Object
- #include_orig ⇒ Object
- #include_without_macros ⇒ Object
-
#includes_module?(mod) ⇒ Boolean
Determine if a class includes a module, in O(n) time.
- #macro(&blk) ⇒ Object
- #macros ⇒ Object
- #private(*args, &block) ⇒ Object
- #remove_method(a) ⇒ Object
- #remove_method_orig ⇒ Object
-
#signature(method, *args) ⇒ Object
Checks that the arguments and return value of a method match the specified signature.
- #type(name, responders, &validator) ⇒ Object
- #undef_method(a) ⇒ Object
- #undef_method_orig ⇒ Object
- #var(*vars) ⇒ Object
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_orig ⇒ Object
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, ) macros.each do |m| base.class_eval m.call( ) 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) = args.last.is_a?(Hash) ? args.pop : {} for mod in args mod.extend_dynamic_object( self, ) 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, ) macros.each do |m| (class << base; self ; end).class_eval m.call( ) end end |
#extend_without_macros ⇒ Object
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) = args.last.is_a?(Hash) ? args.pop : {} for mod in args mod.append_dynamic_features( self, ) end include_without_macros(*args) end |
#include_orig ⇒ Object
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) = args.last.is_a?(Hash) ? args.pop : {} for mod in args mod.append_dynamic_features( self, ) end include_without_macros(*args) end |
#include_without_macros ⇒ Object
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.
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 |
#macros ⇒ Object
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_orig ⇒ Object
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? = {} signature = args.dup .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 .include?(:repeated) if [: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 .include?(:block) then if [:block] then %{raise(ArgumentError, "no block given") unless block} else %{raise(ArgumentError, "block given") if block} end end } #{unless [:allow_trailing] or .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 = [: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 = [: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_orig ⇒ Object
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 |