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

Defined Under Namespace

Modules: Error

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 =

semver gem version

'0.5.0'

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
# 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



55
56
57
58
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
# File 'lib/blobject.rb', line 55

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



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

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



144
145
146
# File 'lib/blobject.rb', line 144

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

Instance Method Details

- (Object) ==(other)

compares Blobjects to Blobjects or Hashes for equality



106
107
108
109
110
# File 'lib/blobject.rb', line 106

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



113
114
115
# File 'lib/blobject.rb', line 113

def [] name
  send name
end

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

hash-like attribute setter



118
119
120
# File 'lib/blobject.rb', line 118

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

- (Object) as_json(*args)

for rails: render json: blobject



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

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)


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

def empty?
  @hash.empty?
end

- (Object) hash

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



40
41
42
# File 'lib/blobject.rb', line 40

def hash
  @hash
end

- (Object) inspect

delegates to the internal Hash



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

def inspect
  @hash.inspect
end

- (Boolean) respond_to?(method)

Returns:

  • (Boolean)


97
98
99
# File 'lib/blobject.rb', line 97

def respond_to? method
  super || self.__respond_to__?(method)
end

- (Boolean) respond_to_missing?(method)

Returns:

  • (Boolean)


101
102
103
# File 'lib/blobject.rb', line 101

def respond_to_missing?(method, *)
  super || self.__respond_to__?(method)
end

- (Object) to_hash

creates a recursive copy of the internal hash



45
46
47
48
49
50
51
# File 'lib/blobject.rb', line 45

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



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

def to_json *args
  as_json.to_json *args
end

- (Object) to_yaml

serialize the Blobject as a yaml string



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

def to_yaml
  as_yaml.to_yaml
end