Class: Prefab::Context

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/prefab/context.rb

Defined Under Namespace

Classes: NamedContext

Constant Summary collapse

BLANK_CONTEXT_NAME =
''
THREAD_KEY =
:prefab_context

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = {}) ⇒ Context

Returns a new instance of Context.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/prefab/context.rb', line 95

def initialize(hash = {})
  @contexts = {}
  @flattened = {}
  @seen_at = Time.now.utc.to_i

  if hash.is_a?(Hash)
    hash.map do |name, values|
      unless values.is_a?(Hash)
        warn "[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash."
        values = { name => values }
        name = BLANK_CONTEXT_NAME
      end

      @contexts[name.to_s] = NamedContext.new(name, values)
      values.each do |key, value|
        @flattened[name.to_s + '.' + key.to_s] = value
      end
    end
  else
    raise ArgumentError, 'must be a Hash'
  end
end

Instance Attribute Details

#contextsObject (readonly)

Returns the value of attribute contexts.



34
35
36
# File 'lib/prefab/context.rb', line 34

def contexts
  @contexts
end

#idObject (readonly)

Returns the value of attribute id.



34
35
36
# File 'lib/prefab/context.rb', line 34

def id
  @id
end

#parentObject (readonly)

Returns the value of attribute parent.



34
35
36
# File 'lib/prefab/context.rb', line 34

def parent
  @parent
end

#seen_atObject (readonly)

Returns the value of attribute seen_at.



34
35
36
# File 'lib/prefab/context.rb', line 34

def seen_at
  @seen_at
end

Class Method Details

.clear_currentObject



79
80
81
# File 'lib/prefab/context.rb', line 79

def clear_current
  Thread.current[THREAD_KEY] = nil
end

.currentObject



59
60
61
# File 'lib/prefab/context.rb', line 59

def current
  Thread.current[THREAD_KEY] ||= join(parent: default_context, id: :block)
end

.current=(context) ⇒ Object



55
56
57
# File 'lib/prefab/context.rb', line 55

def current=(context)
  Thread.current[THREAD_KEY] = join(hash: context || {}, parent: default_context, id: :block)
end

.default_contextObject



51
52
53
# File 'lib/prefab/context.rb', line 51

def default_context
  @default_context ||= join(parent: global_context, id: :default_context)
end

.default_context=(context) ⇒ Object



45
46
47
48
49
# File 'lib/prefab/context.rb', line 45

def default_context=(context)
  @default_context = join(hash: context, parent: global_context, id: :default_context)

  self.current.update_parent(@default_context)
end

.global_contextObject



41
42
43
# File 'lib/prefab/context.rb', line 41

def global_context
  @global_context ||= join(parent: nil, id: :global_context)
end

.global_context=(context) ⇒ Object



37
38
39
# File 'lib/prefab/context.rb', line 37

def global_context=(context)
  @global_context = join(hash: context, parent: nil, id: :global_context)
end

.join(hash: {}, parent: nil, id: :not_provided) ⇒ Object



88
89
90
91
92
93
# File 'lib/prefab/context.rb', line 88

def self.join(hash: {}, parent: nil, id: :not_provided)
  context = new(hash)
  context.update_parent(parent)
  context.instance_variable_set(:@id, id)
  context
end

.merge_with_current(new_context_properties = {}) ⇒ Object



83
84
85
# File 'lib/prefab/context.rb', line 83

def merge_with_current(new_context_properties = {})
  new(current.to_h.merge(new_context_properties.to_h))
end

.with_context(context) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/prefab/context.rb', line 63

def with_context(context)
  old_context = Thread.current[THREAD_KEY]
  Thread.current[THREAD_KEY] = join(parent: default_context, hash: context, id: :block)
  yield
ensure
  Thread.current[THREAD_KEY] = old_context
end

.with_merged_context(context) ⇒ Object



71
72
73
74
75
76
77
# File 'lib/prefab/context.rb', line 71

def with_merged_context(context)
  old_context = Thread.current[THREAD_KEY]
  Thread.current[THREAD_KEY] = join(parent: current, hash: context, id: :merged)
  yield
ensure
  Thread.current[THREAD_KEY] = old_context
end

Instance Method Details

#<=>(other) ⇒ Object



240
241
242
243
244
245
246
# File 'lib/prefab/context.rb', line 240

def <=>(other)
  if other.is_a?(Prefab::Context)
    to_h <=> other.to_h
  else
    super
  end
end

#blank?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/prefab/context.rb', line 122

def blank?
  contexts.empty?
end

#clearObject



173
174
175
176
# File 'lib/prefab/context.rb', line 173

def clear
  @contexts = {}
  @flattened = {}
end

#context(name) ⇒ Object



178
179
180
# File 'lib/prefab/context.rb', line 178

def context(name)
  contexts[name.to_s] || NamedContext.new(name, {})
end

#get(property_key, scope: nil) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/prefab/context.rb', line 133

def get(property_key, scope: nil)
  if !property_key.include?(".")
    property_key = BLANK_CONTEXT_NAME + '.' + property_key
  end

  if @flattened.key?(property_key)
    @flattened[property_key]
  else
    scope ||= property_key.split('.').first

    if @contexts[scope]
      # If the key is in the present scope, parent values should not be used.
      # We can consider the parent value clobbered by the present scope.
      nil
    else
      @parent&.get(property_key, scope: scope)
    end
  end
end

#grouped_keyObject



233
234
235
236
237
# File 'lib/prefab/context.rb', line 233

def grouped_key
  contexts.map do |_, context|
    context.key
  end.sort.join('|')
end

#merge_default(defaults) ⇒ Object



182
183
184
185
186
187
188
# File 'lib/prefab/context.rb', line 182

def merge_default(defaults)
  defaults.keys.each do |name|
    set(name, context(name).merge!(defaults[name]))
  end

  self
end

#reportable_treeObject



190
191
192
193
194
195
196
197
198
199
200
# File 'lib/prefab/context.rb', line 190

def reportable_tree
  ctx = self
  reportables = []

  while ctx
    reportables.unshift(ctx)
    ctx = ctx.parent
  end

  reportables
end

#set(name, hash) ⇒ Object



126
127
128
129
130
131
# File 'lib/prefab/context.rb', line 126

def set(name, hash)
  @contexts[name.to_s] = NamedContext.new(name, hash)
  hash.each do |key, value|
    @flattened[name.to_s + '.' + key.to_s] = value
  end
end

#slim_protoObject



225
226
227
228
229
230
231
# File 'lib/prefab/context.rb', line 225

def slim_proto
  PrefabProto::ContextSet.new(
    contexts: contexts.map do |_, context|
      context.to_proto
    end
  )
end

#to_hObject



153
154
155
# File 'lib/prefab/context.rb', line 153

def to_h
  contexts.transform_values(&:to_h)
end

#to_proto(namespace) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/prefab/context.rb', line 202

def to_proto(namespace)
  prefab_context = {
    'current-time' => ConfigValueWrapper.wrap(Prefab::TimeHelpers.now_in_ms)
  }

  prefab_context['namespace'] = ConfigValueWrapper.wrap(namespace) if namespace&.length&.positive?

  reportable_contexts = {}

  reportable_tree.each do |ctx|
    ctx.contexts.each do |name, context|
      reportable_contexts[name] = context
    end
  end

  PrefabProto::ContextSet.new(
    contexts: reportable_contexts.map do |name, context|
      context.to_proto
    end.concat([PrefabProto::Context.new(type: 'prefab',
                                         values: prefab_context)])
  )
end

#to_sObject



157
158
159
# File 'lib/prefab/context.rb', line 157

def to_s
  "#<Prefab::Context:#{object_id} id=#{@id} #{to_h}>"
end

#tree(depth = 0) ⇒ Object

Visualize a tree of the context up through its parents

example:

| jit: “user”=>{“name”=>“Frank”} |– block: “clock”=>{“timezone”=>“PST”} |—- default_context: “prefab-api-key”=>{“user-id”=>123} |—— global_context: “speed”=>“2.4GHz”, “clock”=>“timezone”=>“UTC”}



169
170
171
# File 'lib/prefab/context.rb', line 169

def tree(depth = 0)
  "|" + ("-" * depth) + " #{id}: #{(" " * (30 - id.to_s.length - depth ))}#{to_h}\n" + (@parent&.tree(depth + 2) || '')
end

#update_parent(parent) ⇒ Object



118
119
120
# File 'lib/prefab/context.rb', line 118

def update_parent(parent)
  @parent = parent
end