Class: DataProvider::Container

Inherits:
Object
  • Object
show all
Defined in:
lib/data_provider/container.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(_opts = {}) ⇒ Container

Returns a new instance of Container.



20
21
22
# File 'lib/data_provider/container.rb', line 20

def initialize _opts = {}
  @options = _opts.is_a?(Hash) ? _opts : {}
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



18
19
20
# File 'lib/data_provider/container.rb', line 18

def options
  @options
end

Instance Method Details

#add(container) ⇒ Object



164
165
166
167
# File 'lib/data_provider/container.rb', line 164

def add(container)
  # make a copy and add the container to that 
  give({}).add!(container)
end

#add!(container) ⇒ Object

adds all the providers defined in the given module to this class



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/data_provider/container.rb', line 145

def add!(container)
  ### add container's providers ###
  # internally providers are added in reverse order (last one first)
  # so at runtime you it's easy and fast to grab the latest provider
  # so when adding now, we have to reverse the providers to get them in the original order
  container.providers.reverse.each do |definition|
    add_provider(*definition)
  end

  ### add container's provides (simple providers) ###
  self.provides(container.provides)

  ### fallback provider ###
  @fallback_provider = container.fallback_provider.block if container.fallback_provider

  ### add container's data ###
  give!(container.data)
end

#add_scoped(container, _options = {}) ⇒ Object

adds all the providers defined in the given module to this class, but turns their identifiers into array and prefixes the array with the :scope option



193
194
195
# File 'lib/data_provider/container.rb', line 193

def add_scoped container, _options = {}
  copy.add_scoped!(container, _options)
end

#add_scoped!(container, _options = {}) ⇒ Object

adds all the providers defined in the given module to this class, but turns their identifiers into array and prefixes the array with the :scope option



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/data_provider/container.rb', line 171

def add_scoped! container, _options = {}
  ### add container's providers ###
  container.providers.reverse.each do |definition|
    identifier = [definition[0]].flatten
    identifier = [_options[:scope]].flatten.compact + identifier if _options[:scope]
    add_provider(*([identifier]+definition[1..-1]))
  end

  ### add container's provides (simple providers) ###
  container.provides.each_pair do |key, value|
    provides(([_options[:scope]].flatten.compact + [key].flatten.compact) => value)
  end

  ### fallback provider ###
  @fallback_provider = container.fallback_provider.block if container.fallback_provider

  ### add container's data ###
  give!(container.data)
end

#copyObject

Data-related methods



201
202
203
204
# File 'lib/data_provider/container.rb', line 201

def copy
  c = self.class.new
  c.add!(self)
end

#current_providerObject



254
255
256
# File 'lib/data_provider/container.rb', line 254

def current_provider
  provider_stack.last
end

#current_skipObject



270
271
272
# File 'lib/data_provider/container.rb', line 270

def current_skip
  (@skip_stack || []).last.to_i
end

#dataObject



206
207
208
# File 'lib/data_provider/container.rb', line 206

def data
  @data || {}
end

#fallback_providerObject



65
66
67
68
# File 'lib/data_provider/container.rb', line 65

def fallback_provider
  block = @fallback_provider
  block.nil? ? nil : Provider.new(nil, nil, block)
end

#fallback_provider?Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/data_provider/container.rb', line 70

def fallback_provider?
  !fallback_provider.nil?
end

#give(_data = {}) ⇒ Object Also known as: add_scope, add_data



210
211
212
# File 'lib/data_provider/container.rb', line 210

def give(_data = {})
  copy.give!(_data)
end

#give!(_data = {}) ⇒ Object Also known as: add_scope!, add_data!



217
218
219
220
221
# File 'lib/data_provider/container.rb', line 217

def give!(_data = {})
  @data ||= {}
  @data.merge!(_data)
  return self
end

#given(param_name) ⇒ Object Also known as: get_data



226
227
228
229
230
231
# File 'lib/data_provider/container.rb', line 226

def given(param_name)
  return data[param_name] if got?(param_name)
  logger.debug "Data provider expected missing data with identifier: #{param_name.inspect}"
  # TODO: raise?
  return nil
end

#got?(param_name) ⇒ Boolean Also known as: has_data?

Returns:

  • (Boolean)


236
237
238
# File 'lib/data_provider/container.rb', line 236

def got?(param_name)
  data.has_key?(param_name)
end

#has_provider?(identifier) ⇒ Boolean

Returns:

  • (Boolean)


34
35
36
# File 'lib/data_provider/container.rb', line 34

def has_provider?(identifier)
  (provides.keys.find{|k| k == identifier} || get_provider(identifier)) != nil
end

#has_providers_with_scope?(args) ⇒ Boolean

Returns:

  • (Boolean)


38
39
40
41
# File 'lib/data_provider/container.rb', line 38

def has_providers_with_scope?(args)
  scope = args.is_a?(Array) ? args : [args]
  provider_identifiers.find{|id| id.is_a?(Array) && id.length > scope.length && id[0..(scope.length-1)] == scope} != nil
end

#loggerObject



24
25
26
27
28
# File 'lib/data_provider/container.rb', line 24

def logger
  @logger ||= options[:logger] || Logger.new(STDOUT).tap do |lger|
    lger.level = Logger::WARN
  end
end

#missing_providerObject



242
243
244
# File 'lib/data_provider/container.rb', line 242

def missing_provider
  @missing_provider
end

#provider(identifier, opts = {}, &block) ⇒ Object



30
31
32
# File 'lib/data_provider/container.rb', line 30

def provider identifier, opts = {}, &block
  add_provider(identifier, opts, block_given? ? block : nil)
end

#provider_idObject



258
259
260
# File 'lib/data_provider/container.rb', line 258

def provider_id
  current_provider ? current_provider.id : nil
end

#provider_identifiersObject



43
44
45
# File 'lib/data_provider/container.rb', line 43

def provider_identifiers
  (provides.keys + providers.map(&:first)).compact.uniq
end

#provider_missing(&block) ⇒ Object



60
61
62
63
# File 'lib/data_provider/container.rb', line 60

def provider_missing &block
  raise "DataProvider::Base#provider_missing expects a block as an argument" if !block_given?
  @fallback_provider = block
end

#provider_stackObject



250
251
252
# File 'lib/data_provider/container.rb', line 250

def provider_stack
  (@stack || []).clone
end

#providersObject



56
57
58
# File 'lib/data_provider/container.rb', line 56

def providers
  @providers || []
end

#provides(_provides = nil) ⇒ Object

provides, when called with a hash param, will define ‘simple providers’ (providers with a simple, static value). When called without a param (or nil) it returns the current cumulative ‘simple providers’ hash



50
51
52
53
54
# File 'lib/data_provider/container.rb', line 50

def provides _provides = nil
  return @provides || {} if _provides.nil?
  add_provides _provides
  return self
end

#scopeObject



266
267
268
# File 'lib/data_provider/container.rb', line 266

def scope
  scopes.last || []
end

#scoped_take(id) ⇒ Object



246
247
248
# File 'lib/data_provider/container.rb', line 246

def scoped_take(id)
  take(scope + [id].flatten)
end

#scopesObject



262
263
264
# File 'lib/data_provider/container.rb', line 262

def scopes
  provider_stack.map{|provider| provider.id.is_a?(Array) ? provider.id[0..-2] : []}
end

#take(id, opts = {}) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/data_provider/container.rb', line 74

def take(id, opts = {})
  logger.debug "DataProvider::Container#take with id: #{id.inspect}"

  # first try the simple providers
  if provides.has_key?(id) && opts[:skip].nil?
    provider = provides[id]
    return provider.is_a?(Proc) ? provider.call : provider
  end

  # try to get a provider object
  provider = get_provider(id, :skip => opts[:skip])
  if provider
    @stack = (@stack || []) + [provider]
    @skip_stack = (@skip_stack || []) + [opts[:skip].to_i]
    result = (opts[:scope] || self).instance_eval(&provider.block) 
    @skip_stack.pop
    @stack.pop
    # execute provider object's block within the scope of self
    return result
  end

  # try to get a scoped provider object
  if scope.length > 0
    scoped_id = [scope, id].flatten
    provider = get_provider(scoped_id, :skip => opts[:skip])
    if provider
      @stack = (@stack || []) + [provider]
      @skip_stack = (@skip_stack || []) + [opts[:skip].to_i]
      result = (opts[:scope] || self).instance_eval(&provider.block) 
      @skip_stack.pop
      @stack.pop
      # execute provider object's block within the scope of self
      return result
    end
  end

  # couldn't find requested provider, let's see if there's a fallback
  if provider = fallback_provider
    # temporarily set the @missing_provider instance variable, so the
    # fallback provider can use it through the missing_provider private method
    @missing_provider = id
    @stack = (@stack || []) + [provider]
    @skip_stack = (@skip_stack || []) + [opts[:skip].to_i]
    result = (opts[:scope] || self).instance_eval(&provider.block) # provider.block.call # with the block.call method the provider can't access private methods like missing_provider
    @skip_stack.pop
    @stack.pop # = nil
    @missing_provider = nil
    return result
  end

  # no fallback either? Time for an error
  raise ProviderMissingException.new(:provider_id => id) 
end

#take_super(opts = {}) ⇒ Object

take_super is only meant to be called form inside a provider returns the result of next provider with the same ID



136
137
138
# File 'lib/data_provider/container.rb', line 136

def take_super(opts = {})
  take(provider_id, opts.merge(:skip => current_skip + 1))
end

#try_take(id, opts = {}) ⇒ Object



128
129
130
131
132
# File 'lib/data_provider/container.rb', line 128

def try_take(id, opts = {})
  return take(id, opts) if self.has_provider?(id) || self.fallback_provider?
  logger.debug "Try for missing provider: #{id.inspect}"
  return nil
end