Class: Ribbon

Inherits:
BasicObject
Defined in:
lib/ribbon.rb,
lib/ribbon/gem.rb,
lib/ribbon/options.rb,
lib/ribbon/wrapper.rb,
lib/ribbon/core_extensions.rb,
lib/ribbon/core_extensions/hash.rb,
lib/ribbon/core_extensions/array.rb,
lib/ribbon/core_extensions/object.rb,
lib/ribbon/core_extensions/basic_object.rb,
lib/ribbon/core_extensions/object/option_scope.rb,
lib/ribbon/core_extensions/object/yield_or_eval.rb

Overview

Ribbons are essentially hashes that use method names as keys.

r = Ribbon.new
r.key = :value

If you access a property that hasn’t been set, a new ribbon will be returned. This allows you to easily work with nested structures:

r.a.b.c = 10

You can also assign properties by passing an argument to the method:

r.a.b.c 20

If you pass a block, the value will be yielded:

r.a do |a|
  a.b do |b|
    b.c 30
  end
end

If the block passed takes no arguments, it will be instance_evaluated in the context of the value instead:

r.a do
  b do
    c 40
  end
end

Appending a bang (!) to the end of the property sets the value and returns the receiver:

Ribbon.new.x!(10).y!(20).z!(30)
 => {x: 10, y: 20, z: 30}

Appending a question mark (?) to the end of the property returns the contents of the property without creating a new ribbon if it is missing:

r.unknown_property?
 => nil

You can use any object as key with the [] and []= operators:

r['/some/path'].entries = []

See Also:

Author:

  • Matheus Afonso Martins Moreira

Since:

  • 0.1.0

Defined Under Namespace

Modules: CoreExtensions Classes: Gem, Options, Wrapper

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = {}, &block) ⇒ Ribbon

Initializes a new ribbon.

If given a block, the ribbon will be yielded to it. If the block doesn’t take any arguments, it will be evaluated in the context of the ribbon.

All objects inside the hash will be converted.

Parameters:

See Also:

Since:

  • 0.1.0



81
82
83
84
85
# File 'lib/ribbon.rb', line 81

def initialize(hash = {}, &block)
  __hash__.merge! ::Ribbon.extract_hash_from(hash)
  __yield_or_eval__ &block
 ::Ribbon.convert_all! self
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Handles the following cases:

ribbon.method                  =>  ribbon[method]
ribbon.method   value          =>  ribbon[method] = value
ribbon.method          &block  =>  ribbon[method, &block]
ribbon.method   value, &block  =>  ribbon[method] = value
                                   ribbon[method, &block]

ribbon.method = value          =>  ribbon[method] = value

ribbon.method!  value          =>  ribbon[method] = value
                                   self
ribbon.method!         &block  =>  ribbon[method, &block]
                                   self
ribbon.method!  value, &block  =>  ribbon[method] = value
                                   ribbon[method, &block]
                                   self

ribbon.method?                 =>  ribbon.__hash__.fetch method
ribbon.method?  value          =>  ribbon.__hash__.fetch method, value
ribbon.method?         &block  =>  ribbon.__hash__.fetch method, &block
ribbon.method?  value, &block  =>  ribbon.__hash__.fetch method, value, &block

Since:

  • 0.1.0



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/ribbon.rb', line 141

def method_missing(method, *args, &block)
  method_string = method.to_s
  key = method_string.strip.gsub(/[=?!]$/, '').strip.intern
  case method_string[-1]
    when ?=
      __send__ :[]=, key, *args
    when ?!
      __send__ :[]=, key, *args unless args.empty?
      self[key, &block]
      self
    when ??
      begin self.__hash__.fetch key, *args, &block
      rescue ::KeyError; nil end
    else
      __send__ :[]=, key, *args unless args.empty?
      self[key, &block]
  end
end

Class Method Details

.convert(object) ⇒ Object

Converts hashes to ribbons. Will look inside arrays.

Parameters:

  • object

    the object to convert

Returns:

  • the converted value

Since:

  • 0.2.0



216
217
218
219
220
221
222
# File 'lib/ribbon.rb', line 216

def convert(object)
  case object
    when Hash then Ribbon.new object
    when Array then object.map { |element| convert element }
    else object
  end
end

.convert_all!(ribbon) ⇒ Ribbon, Ribbon::Wrapper

Converts all values inside the given ribbon.

Parameters:

Returns:

See Also:

Since:

  • 0.2.0



231
232
233
234
235
236
237
238
239
240
# File 'lib/ribbon.rb', line 231

def convert_all!(ribbon)
  ribbon.__hash__.each do |key, value|
    ribbon[key] = case value
      when Ribbon then convert_all! value
      when Ribbon::Wrapper then convert_all! value.ribbon
      else convert value
    end
  end
  ribbon
end

.deep_merge(old_ribbon, new_ribbon) {|key, old_value, new_value| ... } ⇒ Ribbon

Merges everything inside the given ribbons.

Parameters:

Yield Parameters:

  • key

    the key which identifies both values

  • old_value

    the value from old_ribbon

  • new_value

    the value from new_ribbon

Yield Returns:

  • the object that will be used as the new value

Returns:

  • (Ribbon)

    a new ribbon containing the results of the merge

See Also:

Since:

  • 0.4.5



300
301
302
# File 'lib/ribbon.rb', line 300

def deep_merge(old_ribbon, new_ribbon, &block)
  deep :merge, old_ribbon, new_ribbon, &block
end

.deep_merge!(old_ribbon, new_ribbon) {|key, old_value, new_value| ... } ⇒ Ribbon, ...

Merges everything inside the given ribbons in place.

Parameters:

Yield Parameters:

  • key

    the key which identifies both values

  • old_value

    the value from old_ribbon

  • new_value

    the value from new_ribbon

Yield Returns:

  • the object that will be used as the new value

Returns:

See Also:

Since:

  • 0.4.5



320
321
322
# File 'lib/ribbon.rb', line 320

def deep_merge!(old_ribbon, new_ribbon, &block)
  deep :merge!, old_ribbon, new_ribbon, &block
end

.default_value_procProc

Proc used to store a new Ribbon instance as the value of a missing key.

Returns:

  • (Proc)

    the proc used when constructing new hashes

Since:

  • 0.4.6



207
208
209
# File 'lib/ribbon.rb', line 207

def default_value_proc
  @default_value_proc ||= (proc { |hash, key| hash[key] = Ribbon.new })
end

.extract_hash_from(parameter) ⇒ Hash

Returns the hash of a Ribbon. Will attempt to convert other objects.

Parameters:

Returns:

  • (Hash)

    the resulting hash

Since:

  • 0.2.1



356
357
358
359
360
361
362
# File 'lib/ribbon.rb', line 356

def extract_hash_from(parameter)
  case parameter
    when Ribbon::Wrapper then parameter.internal_hash
    when Ribbon then parameter.__hash__
    else parameter.to_hash
  end
end

.from_yaml(string) ⇒ Ribbon

Deserializes the hash from the string using YAML and uses it to construct a new ribbon.

Parameters:

  • string (String)

    a valid YAML string

Returns:

Since:

  • 0.4.7



370
371
372
# File 'lib/ribbon.rb', line 370

def from_yaml(string)
  Ribbon.new YAML.load(string)
end

.instance?(object) ⇒ true, false

Tests whether the given object is an instance of Ribbon.

Parameters:

  • object

    the object to be tested

Returns:

  • (true, false)

    whether the object is an instance of Ribbon

Since:

  • 0.2.0



329
330
331
# File 'lib/ribbon.rb', line 329

def instance?(object)
  Ribbon === object
end

.merge(old_ribbon, new_ribbon) {|key, old_value, new_value| ... } ⇒ Ribbon

Merges the hashes of the given ribbons.

Parameters:

Yield Parameters:

  • key

    the key which identifies both values

  • old_value

    the value from old_ribbon

  • new_value

    the value from new_ribbon

Yield Returns:

  • the object that will be used as the new value

Returns:

  • (Ribbon)

    a new ribbon containing the results of the merge

See Also:

Since:

  • 0.3.0



256
257
258
259
260
261
# File 'lib/ribbon.rb', line 256

def merge(old_ribbon, new_ribbon, &block)
  old_hash = extract_hash_from old_ribbon
  new_hash = extract_hash_from new_ribbon
  merged_hash = old_hash.merge new_hash, &block
  Ribbon.new merged_hash
end

.merge!(old_ribbon, new_ribbon) {|key, old_value, new_value| ... } ⇒ Ribbon, ...

Merges the hashes of the given ribbons in place.

Parameters:

Yield Parameters:

  • key

    the key which identifies both values

  • old_value

    the value from old_ribbon

  • new_value

    the value from new_ribbon

Yield Returns:

  • the object that will be used as the new value

Returns:

See Also:

Since:

  • 0.3.0



278
279
280
281
282
283
# File 'lib/ribbon.rb', line 278

def merge!(old_ribbon, new_ribbon, &block)
  old_hash = extract_hash_from old_ribbon
  new_hash = extract_hash_from new_ribbon
  old_hash.merge! new_hash, &block
  old_ribbon
end

.wrap(object = ::Ribbon.new, &block) ⇒ Ribbon::Wrapper

Wraps an object in a Wrapper.

Parameters:

Returns:

Since:

  • 0.2.0



347
348
349
# File 'lib/ribbon.rb', line 347

def wrap(object = ::Ribbon.new, &block)
  Ribbon::Wrapper.new object, &block
end

.wrapped?(ribbon) ⇒ true, false

Tests whether the given object is an instance of Wrapper.

Parameters:

  • object

    the object to be tested

Returns:

  • (true, false)

    whether the object is an instance of Wrapper

Since:

  • 0.2.0



338
339
340
# File 'lib/ribbon.rb', line 338

def wrapped?(ribbon)
  Ribbon::Wrapper === ribbon
end

Instance Method Details

#[](key, &block) ⇒ Object

Fetches the value associated with the given key.

If given a block, the value will be yielded to it. If the block doesn’t take any arguments, it will be evaluated in the context of the value.

Parameters:

  • key

    the key which identifies the value

Returns:

  • the value associated with the given key

See Also:

  • CoreExt::BasicObject#__yield_or_eval__

Since:

  • 0.1.0



95
96
97
98
99
# File 'lib/ribbon.rb', line 95

def [](key, &block)
  value = ::Ribbon.convert __hash__[key]
  value.__yield_or_eval__ &block
  self[key] = value
end

#[]=(key, *values) ⇒ Object

Associates the given values with the given key.

Examples:

ribbon = Ribbon.new

ribbon[:key] = :value
ribbon[:key]
# => :value

ribbon[:key] = :multiple, :values
ribbon[:key]
# => [:multiple, :values]

Parameters:

  • key

    the key that will identify the values

  • values

    the values that will be associated with the key

Since:

  • 0.1.0



115
116
117
# File 'lib/ribbon.rb', line 115

def []=(key, *values)
  __hash__[key] = if values.size == 1 then values.first else values end
end

#__hash__Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The hash used internally.

Returns:

  • (Hash)

    the hash used by this Ribbon instance to store data

Since:

  • 0.1.0



66
67
68
# File 'lib/ribbon.rb', line 66

def __hash__
  @hash ||= (::Hash.new &::Ribbon.default_value_proc)
end

#to_s(opts = {}) ⇒ String Also known as: inspect

Generates a simple key: value string representation of this ribbon.

Parameters:

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

    a customizable set of options

Options Hash (opts):

  • :separator (String)

    Separates the key/value pair. Default is ': '.

  • :key (Symbol)

    Will be sent to the key in order to convert it to a string. Default is :to_s.

  • :value (Symbol)

    Will be sent to the value in order to convert it to a string. Default is :inspect.

Returns:

  • (String)

    the string representation of this ribbon

Since:

  • 0.1.0



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

def to_s(opts = {})
  __to_s_recursive__ ::Ribbon.extract_hash_from(opts)
end