lib/blobject.rb in blobject-0.3.7 vs lib/blobject.rb in blobject-0.4.0
- old
+ new
@@ -2,11 +2,11 @@
require 'yaml'
require_relative 'blobject/version'
# Wraps a hash to provide arbitrarily nested object-style attribute access
class Blobject
-
+
# filter :to_ary else Blobject#to_ary returns a
# blobject which is not cool, especially if you are puts.
ProhibitedNames = [:to_ary]
# pass an optional hash of values to preload
@@ -25,29 +25,29 @@
end
yield self if block_given?
end
+ # indicates whether the blobject contains any data
def empty?
@hash.empty?
end
# delegates to the internal Hash
def inspect
-
+
@hash.inspect
end
# access the internal hash. be careful, this is _not_ a copy
def hash
-
@hash
end
# creates a recursive copy of the internal hash
def to_hash
-
+
h = hash.dup
@hash.each do |name, node|
h[name] = node.to_hash if node.respond_to? :to_hash
end
h
@@ -61,11 +61,11 @@
case
# assignment in conditionals is usually a bad smell, here it helps minimize regex matching
when (name = method[/^\w+$/, 0]) && params.length == 0
# the call is an attribute reader
-
+
return self.class.new.freeze if frozen? and not @hash.has_key?(method)
self.class.send :__define_attribute__, name
return send(method) if @hash.has_key? method
@@ -97,54 +97,43 @@
super
end
def respond_to? method
-
- return true if self.methods.include?(method)
- return false if ProhibitedNames.include?(method)
+ super || self.__respond_to__?(method)
+ end
- method = method.to_s
-
- [/^(\w+)=$/, /^(\w+)\?$/, /^\w+$/].any? do |r|
- r.match(method)
- end
+ def respond_to_missing?(method, *)
+ super || self.__respond_to__?(method)
end
- # compares Blobjects to Blobjects or Hashes
+ # compares Blobjects to Blobjects or Hashes for equality
def == other
return @hash == other.hash if other.class <= Blobject
return @hash == other if other.class <= Hash
super
end
# hash-like access to the Blobject's attributes
def [] name
-
+
send name
end
- # hash-like attribtue setter
+ # hash-like attribute setter
def []= name, value
-
+
send "#{name.to_s}=", value
end
-
+
# freeze a Blobject to prevent it being modified
def freeze
- @hash.freeze
+ self.class.send(:__freeze_r__, @hash) unless frozen?
super
end
- def freeze_r
- self.class.send(:__freeze_r__, self)
- freeze
- end
-
-
- # returns a hash which can be serialized as json.
- # this is for use in rails controllers: `render json: blobject`
+ # for rails: `render json: blobject`
def as_json *args
return hash.as_json(*args) if hash.respond_to? :as_json
to_hash
end
@@ -153,66 +142,66 @@
as_json.to_json *args
end
# serialize the Blobject as a yaml string
def to_yaml
-
+
as_yaml.to_yaml
end
- # get a Blobject from a json string
- # if the yaml string describes an array, an array will be returned
+ # get a Blobject from a json string, if the yaml string describes an array, an array will be returned
def self.from_json json
-
+
__blobjectify__(JSON.parse(json))
end
- # get a Blobject from a yaml string
- # if the yaml string describes an array, an array will be returned
+ # get a Blobject from a yaml string, if the yaml string describes an array, an array will be returned
def self.from_yaml yaml
-
+
__blobjectify__(YAML.load(yaml))
end
-private
-# to avoid naming collisions private method names are prefixed and suffix with double unerscores (__)
+ protected
+ # to avoid naming collisions private method names are prefixed and suffix with double unerscores (__)
- # Used to tag and reraise errors from a Blobject
+ # Used to tag and re-raise errors from a Blobject
# Refer to "Tagging exceptions with modules" on p97 in Exceptional Ruby by Avdi Grimm
# errors from this library can be handled with rescue Blobject::Error
module Error; end
-
+
def __tag_and_raise__ e
raise e
rescue
e.extend Blobject::Error
raise e
end
+ def __respond_to__?(method)
+ return false if ProhibitedNames.include?(method)
+
+ method = method.to_s
+
+ [/^(\w+)=$/, /^(\w+)\?$/, /^\w+$/].any? do |r|
+ r.match(method)
+ end
+ end
+
class << self
- private
+ protected
def __freeze_r__ object
-
- case object
- when Array
- return object.each do |e|
- e.freeze
- __freeze_r__(e)
- end
- when Hash
- return object.each do |k, v|
+
+ if object.respond_to?(:each) && object.each.is_a?(Enumerator)
+ values = object.is_a?(Hash) ? object.values : object
+ values.each do |v|
v.freeze
__freeze_r__(v)
end
- when Blobject
- object.freeze
- __freeze_r__ object.hash
- else
- object.freeze
end
+
+ object.freeze
end
def __blobjectify__ object
array = object if object.is_a? Array
@@ -234,11 +223,11 @@
unless methods.include? setter_name
self.send :define_method, setter_name do |value|
begin
value = self.class.send(:__blobjectify__, value) if value.is_a?(Hash) or value.is_a?(Array)
@hash[name] = value
- rescue ex
+ rescue => ex
__tag_and_raise__(ex)
end
@store_in_parent.call unless @store_in_parent.nil?
end
end
@@ -246,11 +235,11 @@
unless methods.include? name
self.send :define_method, name do
value = @hash[name]
- if value.nil?
+ if value.nil?
value = self.class.new
@hash[name] = value unless frozen?
end
value
@@ -258,13 +247,13 @@
end
checker_name = (name.to_s + '?').to_sym
unless methods.include? checker_name
self.send :define_method, checker_name do
- @hash.key?(name)
+ @hash[name] ? true : false
end
end
name
end
end
-end
\ No newline at end of file
+end