Class: Blobject

Inherits:
Object
  • Object
show all
Defined in:
lib/blobject.rb,
lib/blobject/version.rb

Overview

Wraps a hash to provide arbitrarily nested, object-style attribute access

Constant Summary

ProhibitedNames =

filter :to_ary else Blobject#to_ary returns a blobject which is not cool, especially if you are puts.

[:to_ary]
VERSION =
'0.3.3'

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Blobject) initialize(hash = {}) {|_self| ... }

pass an optional hash of values to preload you can also pass a block, the new Blobject will be yield

Yields:

  • (_self)

Yield Parameters:

  • _self (Blobject)

    the object that the method was called on



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/blobject.rb', line 14

def initialize hash = {}

  @hash = hash

  @hash.keys.each do |key|
    unless key.class <= Symbol
      value = @hash.delete key
      key = key.to_sym
      @hash[key] = value
    end
  end

  __visit_subtree__ do |name, node|
    if node.class <= Hash
      @hash[name] = Blobject.new node
    end
  end

  yield self if block_given?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

- (Object) method_missing(method, *params, &block)

method_missing is only called the first time an attribute is used. successive calls use memoized getters, setters and checkers



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
# File 'lib/blobject.rb', line 59

def method_missing method, *params, &block

  __tag_and_raise__ NoMethodError.new(method) if ProhibitedNames.include?(method)

  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 nil if frozen? and not @hash.has_key?(method)

    self.class.send :__define_attribute__, name

    return send(method) if @hash.has_key? method

    parent          = self
    nested_blobject = self.class.new

    store_in_parent = lambda do
      parent.send "#{name}=", nested_blobject
      nested_blobject.send :remove_instance_variable, :@store_in_parent
    end

    nested_blobject.instance_variable_set :@store_in_parent, store_in_parent

    return nested_blobject

  when (name = method[/^(\w+)=$/, 1]) && params.length == 1
    # the call is an attribute writer

    self.class.send :__define_attribute__, name
    return send method, params.first

  when (name = method[/^(\w+)\?$/, 1]) && params.length == 0
    # the call is an attribute checker

    self.class.send :__define_attribute__, name
    return send method
  end

  super
end

Class Method Details

+ (Object) from_json(json)

get a Blobject from a json string if the yaml string describes an array, an array will be returned



159
160
161
162
# File 'lib/blobject.rb', line 159

def self.from_json json
  
  __from_hash_or_array__(JSON.parse(json))
end

+ (Object) from_yaml(yaml)

get a Blobject from a yaml string if the yaml string describes an array, an array will be returned



166
167
168
169
# File 'lib/blobject.rb', line 166

def self.from_yaml yaml
  
  __from_hash_or_array__(YAML.load(yaml))
end

Instance Method Details

- (Object) ==(other)

compares Blobjects to Blobjects or Hashes



114
115
116
117
118
# File 'lib/blobject.rb', line 114

def == other
  return @hash == other.hash if other.class <= Blobject
  return @hash == other      if other.class <= Hash
  super
end

- (Object) [](name)

hash-like access to the Blobject's attributes



121
122
123
124
# File 'lib/blobject.rb', line 121

def [] name
  
  send name
end

- (Object) []=(name, value)

hash-like attribtue setter



127
128
129
130
# File 'lib/blobject.rb', line 127

def []= name, value
  
  send "#{name.to_s}=", value
end

- (Object) as_json(*args)

returns a hash which can be serialized as json. this is for use in rails controllers: `render json: blobject`



141
142
143
144
# File 'lib/blobject.rb', line 141

def as_json *args
  return hash.as_json(*args) if hash.respond_to? :as_json
  to_hash
end

- (Object) freeze

freeze a Blobject to prevent it being modified



133
134
135
136
137
# File 'lib/blobject.rb', line 133

def freeze
  __visit_subtree__ { |name, node| node.freeze }
  @hash.freeze
  super
end

- (Object) hash

access the internal hash. be careful, this is not a copy



42
43
44
45
# File 'lib/blobject.rb', line 42

def hash
  
  @hash
end

- (Object) inspect

delegates to the internal Hash



36
37
38
39
# File 'lib/blobject.rb', line 36

def inspect
  
  @hash.inspect
end

- (Boolean) respond_to?(method)

Returns:

  • (Boolean)


101
102
103
104
105
106
107
108
109
110
111
# File 'lib/blobject.rb', line 101

def respond_to? method
  
  return true  if self.methods.include?(method)
  return false if ProhibitedNames.include?(method)

  method = method.to_s

  [/^(\w+)=$/, /^(\w+)\?$/, /^\w+$/].any? do |r|
    r.match(method)
  end
end

- (Object) to_hash

creates a recursive copy of the internal hash



48
49
50
51
52
53
54
55
# File 'lib/blobject.rb', line 48

def to_hash
  
  h = hash.dup
  __visit_subtree__ do |name, node|
    h[name] = node.to_hash if node.respond_to? :to_hash
  end
  h
end

- (Object) to_json(*args)

serialize the Blobject as a json string



147
148
149
# File 'lib/blobject.rb', line 147

def to_json *args
  as_json.to_json *args
end

- (Object) to_yaml

serialize the Blobject as a yaml string



152
153
154
155
# File 'lib/blobject.rb', line 152

def to_yaml
  
  as_yaml.to_yaml
end