Module: HashToObj
- Defined in:
- lib/hash-to-obj.rb,
lib/hash-to-obj/version.rb,
lib/hash-to-obj/default_module.rb
Overview
We extend this to objectify our hashes. It will generate some methods on the hash to access the various keys.
Define a constant HashToObj::SQUELCH_GLOBAL_WARNINGS to squelch warnings about objectify already being defined.
Defined Under Namespace
Modules: DefaultModule
Constant Summary collapse
- DUCK_TYPE_API =
Anything that you want to objectify needs to respond to these methods like a Hash would. If it doesn’t at least respond_to? these methods, an error will be thrown when objectifying.
[:[], :[]=, :each_key].freeze
- VERSION =
:category: Current version of hash-to-obj
'0.3.0'.freeze
Class Method Summary collapse
-
.generate_accessors(hash, key, override_warnings = false) ⇒ Object
Generates the accessors for the passed key on the passed hash.
-
.handle_warnings(hash, key, override_warnings = false) ⇒ Object
This will output any warnings we want to output.
-
.internal_objectify(hash, override_warnings = false, default_module = nil) ⇒ Object
Internal version of objectify.
-
.objectify(hash, options = {}) ⇒ Object
Throws an error if hash doesn’t have all messages defined in DUCK_TYPE_API.
-
.quacks?(obj) ⇒ Boolean
Returns true if the passed object responds to all methods defined in DUCK_TYPE_API.
-
.should_warn?(hash, key) ⇒ Boolean
If there should be a warning, returns the warning message.
-
.valid_key?(key) ⇒ Boolean
Returns a valid method name for the passed key if there is one, otherwise returns false.
Class Method Details
.generate_accessors(hash, key, override_warnings = false) ⇒ Object
Generates the accessors for the passed key on the passed hash. Unless override_warnings is true-y, this will throw errors if we’re gonna screw anything up. If you pass something that responds to :puts in override_warnings then warnings will just be puts’d to that, and things will continue.
91 92 93 94 95 96 97 98 99 |
# File 'lib/hash-to-obj.rb', line 91 def self.generate_accessors(hash, key, override_warnings = false) handle_warnings(hash, key, override_warnings) valid_key = valid_key?(key) hash.define_singleton_method(valid_key) { self[key] } hash.define_singleton_method("#{valid_key}=") do |value| self[key] = value end end |
.handle_warnings(hash, key, override_warnings = false) ⇒ Object
This will output any warnings we want to output.
103 104 105 106 107 108 109 110 111 |
# File 'lib/hash-to-obj.rb', line 103 def self.handle_warnings(hash, key, override_warnings = false) if !override_warnings && should_warn?(hash, key) then if override_warnings.respond_to?(:puts) then override_warnings.puts(should_warn?(hash, key)) else raise ArgumentError, should_warn?(hash, key) end end end |
.internal_objectify(hash, override_warnings = false, default_module = nil) ⇒ Object
Internal version of objectify. Uses seperated arguments instead of options hash.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/hash-to-obj.rb', line 55 def self.internal_objectify(hash, override_warnings = false, default_module = nil) # Make sure it looks SOMEWHAT familiar. unless quacks?(hash) then raise(ArgumentError, "Cannot objectify something that doesn't look like a hash.") end # Now lets actually add those methods. hash.each_key { |key| generate_accessors(hash, key, override_warnings) } hash.extend(default_module) if default_module hash end |
.objectify(hash, options = {}) ⇒ Object
Throws an error if hash doesn’t have all messages defined in DUCK_TYPE_API. Generates the accessors for all keys on the passed hash.
Accepted options:
- override_warnings
-
Unless override_warnings is truthy, this will throw errors if we’re gonna screw anything up. If you pass something that responds to :puts in override_warnings then warnings will just be puts’d to that, and things will continue.
- default_module
-
If a default_module is specified, that will be included in the hash before adding our accessors, essentially allowing you to define a set of methods that should be present after objectifying regardless of the keys in the hash.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/hash-to-obj.rb', line 32 def self.objectify(hash, = {}) if .is_a?(Hash) then internal_objectify(hash, [:override_warnings], [:default_module]) else unless HashToObj.const_defined?(:SQUELCH_GLOBAL_WARNINGS) then puts "objectify(hash, override_warnings) is deprecated.\n"\ ' please use objectify(hash, override_warnings: true) instead.' end # Looks like they're using 0.1.0 API. internal_objectify(hash, ) end end |
.quacks?(obj) ⇒ Boolean
Returns true if the passed object responds to all methods defined in DUCK_TYPE_API.
75 76 77 78 79 80 81 82 83 |
# File 'lib/hash-to-obj.rb', line 75 def self.quacks?(obj) DUCK_TYPE_API.each do |method_sym| unless obj.respond_to?(method_sym) then return false end end true end |
.should_warn?(hash, key) ⇒ Boolean
If there should be a warning, returns the warning message. Otherwise returns false.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/hash-to-obj.rb', line 125 def self.should_warn?(hash, key) valid_key = valid_key?(key) # Make sure its a valid key... return "#{key} is not a valid key." unless valid_key # And make sure they don't have this method... if hash.respond_to?(valid_key) then return "#{hash} already has a #{valid_key} method defined." end if hash.respond_to?("#{valid_key}=") then return "#{hash} already has a #{valid_key}= method defined." end false end |
.valid_key?(key) ⇒ Boolean
Returns a valid method name for the passed key if there is one, otherwise returns false.
116 117 118 119 120 |
# File 'lib/hash-to-obj.rb', line 116 def self.valid_key?(key) regex_match = key.to_s.match(/\A[a-z_][a-z0-9_]*\Z/) return false if regex_match.nil? return key.to_s end |