Class: Showroom::Resource

Inherits:
Object
  • Object
show all
Defined in:
lib/showroom/models/resource.rb

Overview

Base class for all Showroom model objects.

Wraps a plain Hash, providing dot-notation attribute access, association DSL macros (Resource.has_many / Resource.has_one), deep serialization via #to_h, and a configurable #inspect output via Resource.main_attrs.

Examples:

Basic usage

resource = Resource.new('id' => 1, 'title' => 'Foo')
resource.id     # => 1
resource.title  # => "Foo"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = {}) ⇒ Resource

Initializes a Resource from a Hash, normalizing all keys to strings.

Parameters:

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

    attribute data



24
25
26
# File 'lib/showroom/models/resource.rb', line 24

def initialize(hash = {})
  @attrs = hash.transform_keys(&:to_s)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object?

Delegates attribute lookups to @attrs, and caches the method on first call.

Parameters:

  • name (Symbol)

    method name

  • args (Array)

    method arguments (none expected for attr readers)

Returns:

  • (Object, nil)


115
116
117
118
119
120
121
122
123
# File 'lib/showroom/models/resource.rb', line 115

def method_missing(name, *args, &)
  key = name.to_s
  if @attrs.key?(key)
    self.class.define_method(name) { @attrs[key] }
    @attrs[key]
  else
    super
  end
end

Instance Attribute Details

#attrsHash (readonly)

Returns the normalized attribute hash.

Returns:

  • (Hash)

    the normalized attribute hash



16
17
18
# File 'lib/showroom/models/resource.rb', line 16

def attrs
  @attrs
end

#clientShowroom::Client?

Returns the client that fetched this resource.

Returns:



19
20
21
# File 'lib/showroom/models/resource.rb', line 19

def client
  @client
end

Class Method Details

.has_many(name, klass) ⇒ void

This method returns an undefined value.

Defines a reader that wraps the array at attrs[name] as instances of klass.

Parameters:

  • name (Symbol)

    attribute name (plural)

  • klass (Class)

    model class to wrap each element in



50
51
52
53
54
55
56
57
# File 'lib/showroom/models/resource.rb', line 50

def has_many(name, klass) # rubocop:disable Naming/PredicatePrefix
  define_method(name) do
    @attrs[name.to_s] = Array(@attrs[name.to_s]).map do |item|
      item.is_a?(klass) ? item : klass.new(item)
    end
    @attrs[name.to_s]
  end
end

.has_one(name, klass) ⇒ void

This method returns an undefined value.

Defines a reader that wraps the hash at attrs[name] as an instance of klass, or returns nil when absent.

Parameters:

  • name (Symbol)

    attribute name (singular)

  • klass (Class)

    model class to wrap the value in



65
66
67
68
69
70
71
72
# File 'lib/showroom/models/resource.rb', line 65

def has_one(name, klass) # rubocop:disable Naming/PredicatePrefix
  define_method(name) do
    value = @attrs[name.to_s]
    return nil if value.nil?

    value.is_a?(klass) ? value : klass.new(value)
  end
end

.main_attr_keysArray<String>

Returns the list of keys configured via main_attrs.

Returns:

  • (Array<String>)


40
41
42
# File 'lib/showroom/models/resource.rb', line 40

def main_attr_keys
  @main_attrs || []
end

.main_attrs(*keys) ⇒ void

This method returns an undefined value.

Declares which attribute keys are included in #inspect output.

Parameters:

  • keys (Array<Symbol>)

    attribute names to display in inspect



33
34
35
# File 'lib/showroom/models/resource.rb', line 33

def main_attrs(*keys)
  @main_attrs = keys.map(&:to_s)
end

Instance Method Details

#==(other) ⇒ Boolean

Compares two resources by their underlying attribute hashes.

Parameters:

  • other (Object)

Returns:

  • (Boolean)


106
107
108
# File 'lib/showroom/models/resource.rb', line 106

def ==(other)
  other.is_a?(self.class) && other.attrs == @attrs
end

#[](key) ⇒ Object?

Raw access to an attribute by key.

Parameters:

  • key (String, Symbol)

    attribute name

Returns:

  • (Object, nil)


79
80
81
# File 'lib/showroom/models/resource.rb', line 79

def [](key)
  @attrs[key.to_s]
end

#inspectString

Returns a developer-friendly string showing main_attrs values.

Returns:

  • (String)


93
94
95
96
97
98
99
100
# File 'lib/showroom/models/resource.rb', line 93

def inspect
  keys = self.class.main_attr_keys
  pairs = keys.filter_map do |k|
    value = @attrs[k]
    "#{k}: #{value.inspect}" if @attrs.key?(k)
  end
  "#<#{self.class.name} #{pairs.join(', ')}>"
end

#respond_to_missing?(name, include_private = false) ⇒ Boolean

Parameters:

  • name (Symbol)
  • include_private (Boolean) (defaults to: false)

Returns:

  • (Boolean)


128
129
130
# File 'lib/showroom/models/resource.rb', line 128

def respond_to_missing?(name, include_private = false)
  @attrs.key?(name.to_s) || super
end

#to_hHash

Deep-converts the resource (and any nested resources) back to a plain Hash.

Returns:

  • (Hash)


86
87
88
# File 'lib/showroom/models/resource.rb', line 86

def to_h
  @attrs.transform_values { |v| deep_unwrap(v) }
end