Permalink
Browse files

Module-ize class extensions

Start cleaning up structures
  • Loading branch information...
test2049 committed Nov 26, 2008
1 parent c801163 commit a9ec82523b330dcf083dde6c6e9d1b8e8ea8e36b
View
@@ -1,24 +1,31 @@
class Array
- # Assume an array of key, value tuples, and convert to Hash
- def to_hash
- r = {}
- each {|it| r[it[0]] = it[1]}
- return r
- end
+ module ArrayExtensions
+ # Assume an array of key, value tuples, and convert to Hash
+ def to_hash
+ r = {}
+ each {|it| r[it[0]] = it[1]}
+ return r
+ end
- def kind_of_these? y
- inject(false) {|acc, klass| acc || y.kind_of?(klass)}
- end
-
- #return first hash-like element with key k
- def kassoc(k)
- each { |h| return h if h.try(:has_key?, k) }
- return nil
- end
-
- #return first hash-like element with value v
- def vassoc(v)
- each { |h| return h if h.try(:has_value?, v) }
- return nil
+ def kind_of_these? y
+ inject(false) {|acc, klass| acc || y.kind_of?(klass)}
+ end
+
+ #return first hash-like element with key k
+ def kassoc(k)
+ each { |h| return h if h.try(:has_key?, k) }
+ return nil
+ end
+
+ #return first hash-like element with value v
+ def vassoc(v)
+ each { |h| return h if h.try(:has_value?, v) }
+ return nil
+ end
+
+ def extract_options!
+ last.is_a?(::Hash) ? pop : {}
+ end
end
+ include ArrayExtensions
end
View
@@ -1,29 +1,167 @@
class Class
+ module ClassExtensions
+ # Also crazy that this isn't in the library
+ def inherits_from?(klass)
+ return true if self == klass
+ return true if self.superclass == klass
+ return false if self.superclass == Object
- # Also crazy that this isn't in the library
- def inherits_from?(klass)
- return true if self == klass
- return true if self.superclass == klass
- return false if self.superclass == Object
-
- rec = lambda do |x|
- if x == Object
- false
- elsif x == klass
- true
- else
- rec.call(x.superclass)
+ rec = lambda do |x|
+ if x == Object
+ false
+ elsif x == klass
+ true
+ else
+ rec.call(x.superclass)
+ end
end
+
+ rec.call(self)
end
- rec.call(self)
- end
+ def alias_cmethod(to, from)
+ (class << self;self;end).class_eval {
+ define_method to do |*args|
+ send(from, *args)
+ end
+ }
+ end
+
+
+ # Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
+ # their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
+ # to, for example, an array without those additions being shared with either their parent, siblings, or
+ # children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
+ def class_inheritable_reader(*syms)
+ syms.each do |sym|
+ next if sym.is_a?(Hash)
+ class_eval <<-EOS
+def self.#{sym}
+ read_inheritable_attribute(:#{sym})
+end
+
+def #{sym}
+ self.class.#{sym}
+end
+EOS
+ end
+ end
+
+ def class_inheritable_writer(*syms)
+ options = syms.extract_options!
+ syms.each do |sym|
+ class_eval <<-EOS
+ def self.#{sym}=(obj)
+ write_inheritable_attribute(:#{sym}, obj)
+ end
+
+ #{"
+ def #{sym}=(obj)
+ self.class.#{sym} = obj
+ end
+ " unless options[:instance_writer] == false }
+ EOS
+ end
+ end
+
+ def class_inheritable_array_writer(*syms)
+ options = syms.extract_options!
+ syms.each do |sym|
+ class_eval <<-EOS
+ def self.#{sym}=(obj)
+ write_inheritable_array(:#{sym}, obj)
+ end
+
+ #{"
+ def #{sym}=(obj)
+ self.class.#{sym} = obj
+ end
+ " unless options[:instance_writer] == false }
+ EOS
+ end
+ end
+
+ def class_inheritable_hash_writer(*syms)
+ options = syms.extract_options!
+ syms.each do |sym|
+ class_eval <<-EOS
+ def self.#{sym}=(obj)
+ write_inheritable_hash(:#{sym}, obj)
+ end
+
+ #{"
+ def #{sym}=(obj)
+ self.class.#{sym} = obj
+ end
+ " unless options[:instance_writer] == false }
+ EOS
+ end
+ end
+
+ def class_inheritable_accessor(*syms)
+ class_inheritable_reader(*syms)
+ class_inheritable_writer(*syms)
+ end
+
+ def class_inheritable_array(*syms)
+ class_inheritable_reader(*syms)
+ class_inheritable_array_writer(*syms)
+ end
+
+ def class_inheritable_hash(*syms)
+ class_inheritable_reader(*syms)
+ class_inheritable_hash_writer(*syms)
+ end
+
+ def inheritable_attributes
+ @inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
+ end
+
+ def write_inheritable_attribute(key, value)
+ if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
+ @inheritable_attributes = {}
+ end
+ inheritable_attributes[key] = value
+ end
+
+ def write_inheritable_array(key, elements)
+ write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
+ write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
+ end
- def alias_cmethod(to, from)
- (class << self;self;end).class_eval {
- define_method to do |*args|
- send(from, *args)
+ def write_inheritable_hash(key, hash)
+ write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
+ write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
+ end
+
+ def read_inheritable_attribute(key)
+ inheritable_attributes[key]
+ end
+
+ def reset_inheritable_attributes
+ @inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
+ end
+private
+
+ # Prevent this constant from being created multiple times
+ EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
+
+ def inherited_with_inheritable_attributes(child)
+ inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
+
+ if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
+ new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
+ else
+ new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
+ memo.update(key => value.duplicable? ? value.dup : value)
+ end
end
- }
+
+ child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
+ end
end
+
+ include ClassExtensions
+ alias inherited_without_inheritable_attributes inherited
+ alias inherited inherited_with_inheritable_attributes
end
@@ -0,0 +1,37 @@
+class Object
+ # Can you safely .dup this object?
+ # False for nil, false, true, symbols, and numbers; true otherwise.
+ def duplicable?
+ true
+ end
+end
+
+class NilClass #:nodoc:
+ def duplicable?
+ false
+ end
+end
+
+class FalseClass #:nodoc:
+ def duplicable?
+ false
+ end
+end
+
+class TrueClass #:nodoc:
+ def duplicable?
+ false
+ end
+end
+
+class Symbol #:nodoc:
+ def duplicable?
+ false
+ end
+end
+
+class Numeric #:nodoc:
+ def duplicable?
+ false
+ end
+end
View
@@ -1,14 +1,17 @@
class File
- def self.mkfifo(name, mode="666", open_mode="r")
- if File.exists? name and File.pipe? name # Leftover from before
- File.delete name
- end
+ module FileExtensions
+ def self.mkfifo(name, mode="666", open_mode="r")
+ if File.exists? name and File.pipe? name # Leftover from before
+ File.delete name
+ end
- # apalling, but ruby/dl has x-p problems
- if ! File.exists? name
- `mkfifo -m #{ mode } #{ name }`
- end
+ # apalling, but ruby/dl has x-p problems
+ if ! File.exists? name
+ `mkfifo -m #{ mode } #{ name }`
+ end
- return File.open(name, open_mode)
+ return File.open(name, open_mode)
+ end
end
+ include FileExtensions
end
View
@@ -1,22 +1,25 @@
class Fixnum
- # Ridiculous that this isn't in the library.
- def printable?; self >= 0x20 and self <= 0x7e; end
+ module FixnumExtensions
+ # Ridiculous that this isn't in the library.
+ def printable?; self >= 0x20 and self <= 0x7e; end
- # Like Numeric#Step, but yields the length of each span along with
- # the offset. Useful for stepping through data in increments:
- # 0.stepwith(buffer.size, 4096) {|off,len| pp buffer[off,len]}
- # The "len" parameter accounts for the inevitable short final block.
- def stepwith(limit, stepv, &block)
- step(limit, stepv) do |i|
- remt = limit - i
- yield i, remt.cap(stepv)
- end
- end
+ # Like Numeric#Step, but yields the length of each span along with
+ # the offset. Useful for stepping through data in increments:
+ # 0.stepwith(buffer.size, 4096) {|off,len| pp buffer[off,len]}
+ # The "len" parameter accounts for the inevitable short final block.
+ def stepwith(limit, stepv, &block)
+ step(limit, stepv) do |i|
+ remt = limit - i
+ yield i, remt.cap(stepv)
+ end
+ end
- # you can't clone a fixnum? Why?
- def clone; self; end
+ # you can't clone a fixnum? Why?
+ def clone; self; end
- def upper?; self >= 0x41 and self <= 0x5a; end
- def lower?; self >= 0x61 and self <= 0x7a; end
+ def upper?; self >= 0x41 and self <= 0x5a; end
+ def lower?; self >= 0x61 and self <= 0x7a; end
+ end
+ include FixnumExtensions
end
View
@@ -1,6 +1,9 @@
class Hash
- # XXX does the same thing as Hash#invert i think?
- def flip
- map {|k,v| [v,k]}.to_hash
+ module HashExtensions
+ # XXX does the same thing as Hash#invert i think?
+ def flip
+ map {|k,v| [v,k]}.to_hash
+ end
end
+ include HashExtensions
end
Oops, something went wrong.

0 comments on commit a9ec825

Please sign in to comment.