Class: DIDWW::ComplexObject::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/didww/complex_objects/base.rb

Constant Summary collapse

FILTERED =

Redacts sensitive attribute values so credentials never leak into default logs / REPL output / error reports. The on-the-wire payload is unaffected (see ‘#as_json`).

'[FILTERED]'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params = {}) ⇒ Base

Returns a new instance of Base.



81
82
83
84
85
86
# File 'lib/didww/complex_objects/base.rb', line 81

def initialize(params = {})
  params.each { |k, v| self[k] = v }
  self.class.schema.each_property do |property|
    attributes[property.name] = property.default unless attributes.has_key?(property.name) || property.default.nil?
  end
end

Class Method Details

.cast(value, default) ⇒ Object

Type casting for JsonApiClient parser/setters



43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/didww/complex_objects/base.rb', line 43

def cast(value, default)
  case value
  when self
    value
  when Hash
    cast_single_object(value)
  when Array
    value.map { |item| cast(item, item) }
  else
    default
  end
end

.property(name, options = {}) ⇒ Object



14
15
16
17
18
19
20
# File 'lib/didww/complex_objects/base.rb', line 14

def property(name, options = {})
  schema.add(name, options)
  read_only_attributes << name.to_s if options[:read_only]
  sensitive_attributes << name.to_s if options[:sensitive]
  define_method(name.to_sym) { self[name] }
  define_method("#{name}=".to_sym) { |val| self[name] = val }
end

.read_only_attributesObject

Names of attributes that the server returns but does not accept on write. Excluded from ‘as_json` so that round-tripping a resource through PATCH does not echo them back and trigger 400 Param not allowed.



30
31
32
# File 'lib/didww/complex_objects/base.rb', line 30

def read_only_attributes
  @read_only_attributes ||= []
end

.schemaObject



22
23
24
# File 'lib/didww/complex_objects/base.rb', line 22

def schema
  @schema ||= JsonApiClient::Schema.new
end

.sensitive_attributesObject

Names of attributes whose values are credentials/secrets. The wire format is unchanged — ‘as_json` still emits the real values — but `#inspect` redacts them so default logging / error reports / REPL echoes never leak credentials downstream.



38
39
40
# File 'lib/didww/complex_objects/base.rb', line 38

def sensitive_attributes
  @sensitive_attributes ||= []
end

.typeObject

Specifies the JSON API resource type. By default this is inferred from the resource class name.



10
11
12
# File 'lib/didww/complex_objects/base.rb', line 10

def type
  name.demodulize.underscore.pluralize
end

Instance Method Details

#[](key) ⇒ Object



88
89
90
# File 'lib/didww/complex_objects/base.rb', line 88

def [](key)
  attributes[key]
end

#[]=(key, value) ⇒ Object



92
93
94
95
# File 'lib/didww/complex_objects/base.rb', line 92

def []=(key, value)
  property = self.class.schema.find(key)
  attributes[key] = property ? property.cast(value) : value
end

#as_jsonObject

When we represent this resource for serialization (create/update), we do so with this implementation. Read-only attributes are excluded — the server rejects them with 400 Param not allowed.



100
101
102
103
104
105
# File 'lib/didww/complex_objects/base.rb', line 100

def as_json(*)
  excluded = self.class.read_only_attributes
  { type: type }.with_indifferent_access.tap do |h|
    h[:attributes] = attributes.as_json.reject { |k, _| excluded.include?(k.to_s) }
  end
end

#as_json_apiObject



107
# File 'lib/didww/complex_objects/base.rb', line 107

def as_json_api(*); as_json end

#attributesObject



77
78
79
# File 'lib/didww/complex_objects/base.rb', line 77

def attributes
  @attributes ||= ActiveSupport::HashWithIndifferentAccess.new
end

#inspectObject



113
114
115
116
117
118
119
120
# File 'lib/didww/complex_objects/base.rb', line 113

def inspect
  sensitive = self.class.sensitive_attributes
  formatted = attributes.map do |k, v|
    display = sensitive.include?(k.to_s) && !v.nil? ? FILTERED : v
    "#{k}=#{display.inspect}"
  end
  "#<#{self.class.name} #{formatted.join(' ')}>"
end

#typeObject



73
74
75
# File 'lib/didww/complex_objects/base.rb', line 73

def type
  self.class.type
end