Class: Attributor::Flatpack::Config

Inherits:
Hash
  • Object
show all
Defined in:
lib/attributor/flatpack/config.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data = nil) ⇒ Config

Returns a new instance of Config.



40
41
42
43
44
45
46
47
# File 'lib/attributor/flatpack/config.rb', line 40

def initialize(data = nil)
  @raw = data
  @contents = {}

  self.class.keys.each do |k, _v|
    self.define_accessors(k)
  end
end

Class Method Details

.example(context = nil, **values) ⇒ Object



32
33
34
35
36
37
38
# File 'lib/attributor/flatpack/config.rb', line 32

def self.example(context = nil, **values)
  example = super
  # Need the @raw to be set as well, since we're using it in fetch
  contents = example.instance_variable_get(:@contents)
  example.instance_variable_set(:@raw, contents.dup)
  example
end

.from_hash(object, _context, **_opts) ⇒ Object



27
28
29
30
# File 'lib/attributor/flatpack/config.rb', line 27

def self.from_hash(object, _context, **_opts)
  config = new(object)
  config
end

.inherited(klass) ⇒ Object



17
18
19
20
21
22
23
24
25
# File 'lib/attributor/flatpack/config.rb', line 17

def self.inherited(klass)
  super
  sep = self.separator
  klass.instance_eval do
    @separator = sep
  end
  klass.options[:dsl_compiler] = ConfigDSLCompiler
  klass.options[:allow_extra] = true
end

.separator(sep = nil) ⇒ Object



10
11
12
13
14
# File 'lib/attributor/flatpack/config.rb', line 10

def separator(sep = nil)
  return @separator unless sep

  @separator = sep
end

Instance Method Details

#[](key) ⇒ Object



134
135
136
# File 'lib/attributor/flatpack/config.rb', line 134

def [](key)
  get key
end

#[]=(key, val) ⇒ Object



138
139
140
# File 'lib/attributor/flatpack/config.rb', line 138

def []=(key, val)
  set key, val
end

#_get(key, attribute:, context:) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/attributor/flatpack/config.rb', line 85

def _get(key, attribute:, context:)
  if attribute.type < Attributor::Flatpack::Config
    top = fetch(key) do
      {}
    end
    attribute.load(top, context).merge!(subselect(key))
  else
    value = fetch(key) do
      # raise "couldn't find #{key.inspect} anywhere"
      nil
    end
    attribute.load(value, context)
  end
end

#default_context(key) ⇒ Object



75
76
77
# File 'lib/attributor/flatpack/config.rb', line 75

def default_context(key)
  generate_subcontext(Attributor::DEFAULT_ROOT_CONTEXT, key)
end

#define_accessors(name) ⇒ Object



49
50
51
52
# File 'lib/attributor/flatpack/config.rb', line 49

def define_accessors(name)
  define_reader(name)
  define_writer(name)
end

#define_reader(name) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/attributor/flatpack/config.rb', line 54

def define_reader(name)
  context = default_context(name)
  define_singleton_method(name) do
    get(name, context: context)
  end

  attribute = self.class.keys[name]
  return unless attribute.type == Attributor::Boolean

  define_singleton_method(name.to_s + '?') do
    !!get(name, attribute: attribute, context: context)
  end
end

#define_writer(name) ⇒ Object



68
69
70
71
72
73
# File 'lib/attributor/flatpack/config.rb', line 68

def define_writer(name)
  context = ['assignment', "of(#{name})"].freeze
  define_singleton_method(name.to_s + '=') do |value|
    set(name, value, context: context)
  end
end

#dump(**opts) ⇒ Object



194
195
196
197
198
# File 'lib/attributor/flatpack/config.rb', line 194

def dump(**opts)
  # quick hack to ensure we load all the values into @contents
  self.validate
  super
end

#fetch(key) ⇒ Object

search @raw for key



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/attributor/flatpack/config.rb', line 111

def fetch(key)
  return @raw[key] if @raw.key?(key)

  found_key, found_value = @raw.find do |(k, _v)|
    k.to_s.casecmp(key.to_s).zero?
  end

  return found_value if found_key

  yield if block_given?
end

#get(key, context: default_context(key), attribute: ) ⇒ Object

Raises:



79
80
81
82
83
# File 'lib/attributor/flatpack/config.rb', line 79

def get(key, context: default_context(key), attribute: self.class.keys[key])
  raise UndefinedKey.new(key, context) unless attribute

  @contents[key] ||= _get(key, attribute: attribute, context: context)
end

#merge!(other) ⇒ Object



142
143
144
145
146
147
148
149
# File 'lib/attributor/flatpack/config.rb', line 142

def merge!(other)
  # Not sure if we need to nuke the memozied set of loaded stuff here
  # or not... but it sounds like a good idea.
  @contents = {}
  @raw.merge!(other)

  self
end

#pretty_print(context: []) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
# File 'lib/attributor/flatpack/config.rb', line 182

def pretty_print(context: [])
  self.collect do |k, v|
    sub_context = context + [k]
    case v
    when Attributor::Flatpack::Config
      v.pretty_print(context: context | [k])
    else
      "#{sub_context.join('.')}=#{v.inspect}"
    end
  end.flatten
end

#set(key, value, context: default_context(key)) ⇒ Object



100
101
102
103
104
105
106
107
108
# File 'lib/attributor/flatpack/config.rb', line 100

def set(key, value, context: default_context(key))
  attribute = self.class.keys.fetch key do
    raise UndefinedKey.new(key, [key])
  end

  loaded = attribute.load(value, context)
  @contents[key] = loaded
  @raw[key] = loaded
end

#subselect(prefix) ⇒ Object



123
124
125
126
127
128
129
130
131
132
# File 'lib/attributor/flatpack/config.rb', line 123

def subselect(prefix)
  prefix_match = /^#{prefix}#{::Regexp.escape(self.class.separator)}(.*)/i

  selected = @raw.collect do |(k, v)|
    if (match = prefix_match.match(k))
      [match[1], v]
    end
  end.compact
  ::Hash[selected]
end

#validate(context = Attributor::DEFAULT_ROOT_CONTEXT) ⇒ Object

shamelessly copied from Attributor::Model’s #validate :(



152
153
154
155
156
# File 'lib/attributor/flatpack/config.rb', line 152

def validate(context = Attributor::DEFAULT_ROOT_CONTEXT)
  self.validate_attributes(context) +
    self.validate_requirements(context) +
    self.validate_keys(context)
end

#validate_attributes(context) ⇒ Object



158
159
160
161
162
163
164
# File 'lib/attributor/flatpack/config.rb', line 158

def validate_attributes(context)
  self.class.attributes.each_with_object([]) do |(name, attr), errors|
    sub_context = self.generate_subcontext(context, name)
    value = self.get(name)
    errors.push(*attr.validate(value, sub_context))
  end
end

#validate_keys(context) ⇒ Object



172
173
174
175
176
177
178
179
180
# File 'lib/attributor/flatpack/config.rb', line 172

def validate_keys(context)
  return [] if self.class.options[:allow_extra]

  errors = (@raw.keys.collect(&:to_s) - self.class.keys.keys.collect(&:to_s)).collect do |extra_key|
    "Unknown key received: #{extra_key.inspect} for #{Attributor.humanize_context(context)}"
  end

  errors
end

#validate_requirements(context) ⇒ Object



166
167
168
169
170
# File 'lib/attributor/flatpack/config.rb', line 166

def validate_requirements(context)
  self.class.requirements.each_with_object([]) do |req, errors|
    errors.push(req.validate(@contents, context))
  end
end