Class: Structure

Inherits:
Object
  • Object
show all
Defined in:
lib/structure.rb,
lib/structure/version.rb,
lib/structure/ext/active_support.rb

Overview

Structure is a key/value container. On the most basic level, it mirrors the functionality of OpenStruct:

require 'structure'

record = Structure.new
record.name    = "John Smith"
record.age     = 70
record.pension = 300

puts record.name    # -> "John Smith"
puts record.address # -> nil

Build structures recursively:

hash = {
 "name"       => "Australia",
 "population" => "20000000",
 "cities"     => [
   {
     "name"       => "Sydney",
     "population" => "4100000"
   },
   {
     "name"       => "Melbourne",
     "population" => "4000000"
   } ]
 }

 country = Structure.new(hash)
 puts country.name              # -> "Australia"
 puts country.cities.count      # -> 2
 puts country.cities.first.name # -> "Sydney"

Define optionally-typed fields in a structure:

class Price < Structure
  field :cents, Integer
  field :currency, :default => "USD"
end

hash = { "cents" => "100" }

price = Price.new(hash)
puts price.cents    # -> 100
puts price.currency # -> "USD"

Alternatively, define a proc to cast or otherwise manipulate assigned values:

class Product < Structure
  field :sku, lambda(&:upcase)
end

product = Product.new(:sku => 'foo-bar')
puts product.sku # -> "FOO-BAR"

Structures are fully conversant in JSON, which is quite handy in the ephemeral landscape of APIs.

Constant Summary collapse

VERSION =
'0.23.1'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hsh = {}) ⇒ Structure

Creates a new structure.

Parameters:

  • hsh (Hash) (defaults to: {})

    an optional hash to populate fields



117
118
119
120
121
122
123
124
125
126
127
# File 'lib/structure.rb', line 117

def initialize(hsh = {})
  # It may have improved performance if I had defined these methods
  # on the class level, but I decided to privilege consistency here.
  # Who wouldn't?
  @table = blueprint.inject({}) do |a, (k, v)|
    default = v[:default].dup rescue v[:default]
    a.merge new_field(k, v[:type]) => default
  end

  marshal_load(hsh)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(mth, *args) ⇒ Object (private)



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/structure.rb', line 185

def method_missing(mth, *args)
  name = mth.to_s
  len = args.length
  if name.chomp!('=') && mth != :[]=
    modifiable[new_field(name)] = recursively_load(args.first)
  elsif len == 0
    @table[new_field(mth)]
  else
    super
  end
end

Class Method Details

.field(key, opts = {}) ⇒ Object .field(key, type, opts = {}) ⇒ Object

Creates a field.

Overloads:

  • .field(key, opts = {}) ⇒ Object

    Creates a field.

    Parameters:

    • key (#to_sym)

      the name of the field

    • opts (Hash) (defaults to: {})

      the options to create the field with

    Options Hash (opts):

    • :default (Object)

      the default value

  • .field(key, type, opts = {}) ⇒ Object

    Creates a typed field.

    Parameters:

    • key (#to_sym)

      the name of the field

    • type (Class, Proc)

      the type to cast assigned values

    • opts (Hash) (defaults to: {})

      the options to create the field with

    Options Hash (opts):

    • :default (Object)

      the default value



91
92
93
94
95
96
97
# File 'lib/structure.rb', line 91

def field(key, *args)
  opts = args.last.is_a?(Hash) ? args.pop : {}
  default = opts[:default]
  type = args.shift
  @blueprint[key] = { :type    => type,
                      :default => default }
end

.json_create(hsh) ⇒ Structure

Builds a structure out of a JSON representation.

Parameters:

  • hsh (Hash)

    a JSON representation translated to a hash

Returns:



74
75
76
77
# File 'lib/structure.rb', line 74

def json_create(hsh)
  hsh.delete('json_class')
  new(hsh)
end

.many(key) ⇒ Object

Syntactic sugar to create a typed field that defaults to an empty array.

Parameters:

  • key

    the name of the field



102
103
104
# File 'lib/structure.rb', line 102

def many(key)
  field(key, Array, :default => [])
end

Instance Method Details

#==(other) ⇒ Boolean

Returns whether the object and other are equal.

Returns:

  • (Boolean)

    whether the object and other are equal



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

def ==(other)
  other.is_a?(Structure) && @table == other.table
end

#delete_field(key) ⇒ Object

Deletes a field.

Parameters:

  • key (#to_sym)

Returns:

  • (Object)

    the value of the deleted field



132
133
134
135
136
137
138
139
# File 'lib/structure.rb', line 132

def delete_field(key)
  key = key.to_sym
  class << self; self; end.class_eval do
    [key, "#{key}="].each { |m| remove_method m }
  end

  @table.delete key
end

#marshal_dumpHash

Provides marshalling support for use by the Marshal library.

Returns:

  • (Hash)

    a hash of the keys and values of the structure



143
144
145
146
147
# File 'lib/structure.rb', line 143

def marshal_dump
  @table.inject({}) do |a, (k, v)|
    a.merge k => recursively_dump(v)
  end
end

#marshal_load(hsh) ⇒ Object

Provides marshalling support for use by the Marshal library. structure

Parameters:

  • hsh (Hash)

    a hash of keys and values to populate the



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

def marshal_load(hsh)
  hsh.each do |k, v|
    self.send("#{new_field(k)}=", v)
  end
end

#to_json(*args) ⇒ String

Returns a JSON representation of the structure.

Returns:

  • (String)

    a JSON representation of the structure



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

def to_json(*args)
  { JSON.create_id => self.class.name }.
    merge(marshal_dump).
    to_json(*args)
end