Class: Fopost::Model
- Inherits:
-
Object
show all
- Defined in:
- lib/fopost/model.rb
Overview
Base for every response model.
The API is not consistent about its wire casing — posts come back
snake_case, accounts camelCase, workspaces a mix — so every key is
normalised to a snake_case symbol before it is read. Unknown keys are kept
on #raw rather than dropped, so a server-side addition never breaks a
client.
Direct Known Subclasses
AiCreditBalance, AiCredits, CaptionResult, ContentBlock, Delivery, Label, MediaItem, PageMeta, Post, PostAccount, RepurposeResult, RewriteResult, RewriteVariant, SocialAccount, Workspace
Instance Attribute Summary collapse
-
#raw ⇒ Object
readonly
The decoded body exactly as the API sent it.
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(data = {}) ⇒ Model
Returns a new instance of Model.
64
65
66
67
68
69
70
71
72
|
# File 'lib/fopost/model.rb', line 64
def initialize(data = {})
@raw = data.is_a?(Hash) ? data : {}
normalized = self.class.normalize(@raw)
@attributes = {}
self.class.attribute_types.each do |name, type|
@attributes[name] = self.class.coerce(type, normalized[name])
end
@normalized = normalized
end
|
Instance Attribute Details
#raw ⇒ Object
The decoded body exactly as the API sent it.
62
63
64
|
# File 'lib/fopost/model.rb', line 62
def raw
@raw
end
|
Class Method Details
.attribute(name, type = nil) ⇒ Object
type is nil (pass through), :time, :hash, a Model subclass, or a
one-element array holding a Model subclass.
21
22
23
24
|
# File 'lib/fopost/model.rb', line 21
def attribute(name, type = nil)
attribute_types[name] = type
define_method(name) { @attributes[name] }
end
|
.attribute_types ⇒ Object
15
16
17
|
# File 'lib/fopost/model.rb', line 15
def attribute_types
@attribute_types ||= superclass.respond_to?(:attribute_types) ? superclass.attribute_types.dup : {}
end
|
.coerce(type, value) ⇒ Object
40
41
42
43
44
45
46
47
48
49
50
51
|
# File 'lib/fopost/model.rb', line 40
def coerce(type, value)
case type
when nil then value
when :time then parse_time(value)
when :hash then value.is_a?(Hash) ? value : {}
when Array
member = type.first
value.is_a?(Array) ? value.map { |item| member.new(item) } : []
else
value.is_a?(Hash) ? type.new(value) : nil
end
end
|
.normalize(data) ⇒ Object
34
35
36
37
38
|
# File 'lib/fopost/model.rb', line 34
def normalize(data)
return {} unless data.is_a?(Hash)
data.each_with_object({}) { |(key, value), out| out[snake(key)] = value }
end
|
.parse_time(value) ⇒ Object
53
54
55
56
57
58
|
# File 'lib/fopost/model.rb', line 53
def parse_time(value)
case value
when Time then value
when String then Time.iso8601(value) rescue (Time.parse(value) rescue nil)
end
end
|
.snake(key) ⇒ Object
26
27
28
29
30
31
32
|
# File 'lib/fopost/model.rb', line 26
def snake(key)
key.to_s
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
.downcase
.to_sym
end
|
Instance Method Details
#==(other) ⇒ Object
Also known as:
eql?
86
87
88
|
# File 'lib/fopost/model.rb', line 86
def ==(other)
other.class == self.class && other.raw == raw
end
|
#[](key) ⇒ Object
Read a field the SDK does not model yet, by either wire spelling.
75
76
77
78
79
80
|
# File 'lib/fopost/model.rb', line 75
def [](key)
name = self.class.snake(key)
return @attributes[name] if @attributes.key?(name)
@normalized[name]
end
|
#hash ⇒ Object
91
92
93
|
# File 'lib/fopost/model.rb', line 91
def hash
[self.class, raw].hash
end
|
#inspect ⇒ Object
95
96
97
98
99
|
# File 'lib/fopost/model.rb', line 95
def inspect
shown = @attributes.reject { |_, value| value.nil? || value == [] || value == {} }
fields = shown.map { |name, value| "#{name}=#{value.inspect}" }.join(' ')
"#<#{self.class.name}#{" #{fields}" unless fields.empty?}>"
end
|
#to_h ⇒ Object
82
83
84
|
# File 'lib/fopost/model.rb', line 82
def to_h
@attributes.dup
end
|