Class: Julewire::Core::Fields::FieldStack

Inherits:
Object
  • Object
show all
Defined in:
lib/julewire/core/fields/field_stack.rb

Overview

Immutable layers keep snapshots stable while each stack tracks only its current head and versioned read caches.

Instance Method Summary collapse

Constructor Details

#initialize(fields = {}, delete_paths: false, source: nil) ⇒ FieldStack

Returns a new instance of FieldStack.



140
141
142
143
144
145
146
147
148
# File 'lib/julewire/core/fields/field_stack.rb', line 140

def initialize(fields = {}, delete_paths: false, source: nil)
  @source = source
  @delete_paths_enabled = delete_paths
  @version = 0
  @snapshot_version = nil
  @snapshot = nil
  @value_cache = nil
  add(fields) if fields.is_a?(Hash) && !fields.empty?
end

Instance Method Details

#add(fields = nil, owned: false, **keyword_fields) ⇒ Object



178
179
180
181
182
183
184
185
186
# File 'lib/julewire/core/fields/field_stack.rb', line 178

def add(fields = nil, owned: false, **keyword_fields)
  fields = field_input(fields, keyword_fields, owned: owned)
  return unless fields.is_a?(Hash)
  return if fields.empty?

  fields = normalize_owned_keys(fields) if owned
  @source = Layer.new(@source, fields, clear_parent_deletes: true)
  invalidate_snapshot!
end

#delete(path) ⇒ Object



188
189
190
191
192
193
194
# File 'lib/julewire/core/fields/field_stack.rb', line 188

def delete(path)
  return if path.empty?
  return unless @delete_paths_enabled

  @source = Layer.new(@source, {}, delete_paths: [path], clear_parent_deletes: false)
  invalidate_snapshot!
end

#forkObject



158
159
160
# File 'lib/julewire/core/fields/field_stack.rb', line 158

def fork
  self.class.new(delete_paths: @delete_paths_enabled, source: @source)
end

#snapshotObject



150
151
152
153
154
155
156
# File 'lib/julewire/core/fields/field_stack.rb', line 150

def snapshot
  return @snapshot if @snapshot_version == @version

  @snapshot = @source ? @source.snapshot : EMPTY_HASH
  @snapshot_version = @version
  @snapshot
end

#value_for(key, default:) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/julewire/core/fields/field_stack.rb', line 162

def value_for(key, default:)
  cache = @value_cache
  return cache[key] if cache&.key?(key)

  if key.is_a?(String)
    key = Fields::Internal.normalize_key(key)
    cache = @value_cache
    return cache[key] if cache&.key?(key)
  end

  value = source_value_for(key)
  return default if value.equal?(MISSING)

  (@value_cache ||= {})[key] = value
end

#with(fields = nil, owned: false, **keyword_fields) ⇒ Object



196
197
198
199
200
201
202
203
# File 'lib/julewire/core/fields/field_stack.rb', line 196

def with(fields = nil, owned: false, **keyword_fields, &)
  fields = field_input(fields, keyword_fields, owned: owned)
  return yield unless fields.is_a?(Hash)
  return yield if fields.empty?

  fields = normalize_owned_keys(fields) if owned
  with_layer(fields, &)
end

#without(path) ⇒ Object

Raises:

  • (ArgumentError)


205
206
207
208
209
210
211
# File 'lib/julewire/core/fields/field_stack.rb', line 205

def without(path, &)
  raise ArgumentError, "field path is required" if path.empty?

  return yield unless @delete_paths_enabled

  with_layer({}, delete_paths: [path], &)
end