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 :toary else Blobject#toary returns a blobject which is not cool, especially if you are puts.

[:to_ary]
VERSION =

semver gem version

'0.3.8'

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

def initialize hash = {}

  @hash = Hash.new

  hash.each do |key, value|
    key = key.to_sym unless key.is_a? Symbol
    @hash[key] = value
  end

  @hash.each do |name, node|
    @hash[name] = self.class.send(:__blobjectify__, node)
  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
100
# 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 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

    # close the scope for storing call chain
    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



164
165
166
167
# File 'lib/blobject.rb', line 164

def self.from_json json
  
  __blobjectify__(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



170
171
172
173
# File 'lib/blobject.rb', line 170

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

Instance Method Details

- (Object) ==(other)

compares Blobjects to Blobjects or Hashes for equality



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

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



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

def [] name
  
  send name
end

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

hash-like attribute setter



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

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

- (Object) as_json(*args)

for rails: render json: blobject



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

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

- (Boolean) empty?

indicates whether the blobject contains any data

Returns:

  • (Boolean)


31
32
33
# File 'lib/blobject.rb', line 31

def empty?
  @hash.empty?
end

- (Object) freeze

freeze a Blobject to prevent it being modified



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

def freeze
  @hash.freeze
  super
end

- (Object) freeze_r

recursively freeze the Blobject include nest Blobjects in arrays



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

def freeze_r
  self.class.send(:__freeze_r__, self)
  freeze
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)


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

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
  @hash.each 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



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

def to_json *args
  as_json.to_json *args
end

- (Object) to_yaml

serialize the Blobject as a yaml string



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

def to_yaml
  
  as_yaml.to_yaml
end