lib/citeproc/attributes.rb in citeproc-0.0.8 vs lib/citeproc/attributes.rb in citeproc-0.0.9
- old
+ new
@@ -1,124 +1,131 @@
-
module CiteProc
-
- # TODO refactor using a Struct instead of a hash. This will have to convert
- # the CiteProc/CSL names which are no proper method names.
-
-
+
module Attributes
extend Forwardable
-
- FALSE_PATTERN = (/^(false|no|never)$/i).freeze
-
def self.included(base)
base.extend(ClassMethods)
end
def attributes
@attributes ||= {}
end
- def_delegators :attributes, :length, :empty?
+ def_delegators :attributes, :length, :empty?, :values_at, :key?, :value?
- def [](key)
- attributes[filter_key(key)]
- end
-
- def []=(key, value)
- attributes[filter_key(key)] = filter_value(value)
- end
-
- def filter_key(key)
- key.to_sym
- end
-
- def filter_value(value, key = nil)
- value.respond_to?(:deep_copy) ? value.deep_copy : value.dup
- rescue
- value
- end
-
+ alias size length
+
+ def [](key)
+ attributes[filter_key(key)]
+ end
+
+ def []=(key, value)
+ attributes[filter_key(key)] = filter_value(value)
+ end
+
+ def filter_key(key)
+ key.to_sym
+ end
+
+ def filter_value(value, key = nil)
+ value.respond_to?(:deep_copy) ? value.deep_copy : value.dup
+ rescue
+ value
+ end
+
def merge(other)
return self if other.nil?
- case other
- when String, /^\s*\{/
- other = MulitJson.decode(other, :symbolize_keys => true)
- when Hash
- # do nothing
- when Attributes
+ case
+ when other.is_a?(String) && /^\s*\{/ =~ other
+ other = MultiJson.decode(other, :symbolize_keys => true)
+ when other.respond_to?(:each_pair)
+ # do nothing
+ when other.respond_to?(:to_hash)
other = other.to_hash
- else
- raise ParseError, "failed to merge attributes and #{other.inspect}"
+ else
+ raise ParseError, "failed to merge attributes and #{other.inspect}"
end
other.each_pair do |key, value|
- attributes[filter_key(key)] = filter_value(value, key)
- end
-
+ attributes[filter_key(key)] = filter_value(value, key)
+ end
+
self
end
alias update merge
- def reverse_merge(other)
- fail "not implemented yet"
- end
+ def reverse_merge(other)
+ fail "not implemented yet"
+ end
- def to_hash
- attributes.deep_copy
- end
+ def to_hash
+ attributes.deep_copy
+ end
- def to_citeproc
- Hash[*attributes.map { |k,v|
- [k.to_s, v.respond_to?(:to_citeproc) ? v.to_citeproc : v.to_s]
- }.flatten(1)]
- end
-
- def to_json
- MultiJson.encode(to_citeproc)
- end
+ # @return [Hash] a hash-based representation of the attributes
+ def to_citeproc
+ Hash[attributes.map { |k,v|
+ [k.to_s, v.respond_to?(:to_citeproc) ? v.to_citeproc : v.to_s]
+ }]
+ end
+
+ # @return [String] a JSON string representation of the attributes
+ def to_json
+ MultiJson.encode(to_citeproc)
+ end
- # Don't expose internals to public API
- private :filter_key, :filter_value
-
- # initialize_copy should be able to access attributes
- protected :attributes
-
+ # Don't expose internals to public API
+ private :filter_key, :filter_value
+
+ # initialize_copy should be able to access attributes
+ protected :attributes
-
- # def eql?(other)
- # case
- # when equal?(other)
- # true
- # when self.class != other.class, length != other.length
- # false
- # else
- # other.attributes.each_pair do |key, value|
- # return false unless attributes[key].eql?(value)
- # end
- #
- # true
- # end
- # end
- #
- # def hash
- # end
-
+
+ # Two Attribute-based objects are equal if they are the same object,
+ # or if all their attributes are equal using _#eql?_.
+ #
+ # @param other [Object] the other object
+ # @return [Boolean] whether or not self and passed-in object are equal
+ def eql?(other)
+ case
+ when equal?(other)
+ true
+ when self.class != other.class, length != other.length
+ false
+ else
+ other.attributes.each_pair do |key, value|
+ return false unless attributes[key].eql?(value)
+ end
+
+ true
+ end
+ end
+
+ # @return [Fixnum] a hash value based on the object's attributes
+ def hash
+ digest = size
+ attributes.each do |attribute|
+ digest ^= attribute.hash
+ end
+
+ digest
+ end
+
module ClassMethods
- def create(parameters)
- create!(parameters)
- rescue
- nil
- end
+ def create(parameters)
+ create!(parameters)
+ rescue
+ nil
+ end
- def create!(parameters)
- new.merge(parameters)
- end
+ def create!(parameters)
+ new.merge(parameters)
+ end
def attr_predicates(*arguments)
arguments.flatten.each do |field|
field, default = *(field.is_a?(Hash) ? field.to_a.flatten : [field]).map(&:to_s)
attr_field(field, default, true)
@@ -150,15 +157,15 @@
unless instance_methods.include?(writer_id)
define_method(writer_id) do |value|
attributes[field.to_sym] = value
end
end
-
+
predicate_id = [method_id, '?'].join
if predicate && !instance_methods.include?(predicate_id)
define_method(predicate_id) do
- v = attributes[field.to_sym]
- !(v.nil? || (v.respond_to?(:empty?) && v.empty?) || v =~ FALSE_PATTERN)
+ v = attributes[field.to_sym]
+ !(!v || (v.respond_to?(:empty?) && v.empty?) || v.to_s =~ /^(false|no|never)$/i)
end
has_predicate = ['has_', predicate_id].join
alias_method(has_predicate, predicate_id) unless instance_methods.include?(has_predicate)
end
\ No newline at end of file