Class: Brut::Framework::Container
- Inherits:
-
Object
- Object
- Brut::Framework::Container
- Defined in:
- lib/brut/framework/container.rb
Overview
This is a basic container for shared context, configuration, and objects. This allows easily sharing cross-cutting information such as project root, environment, and other objects.
This can be used to store configuration values, re-usable objects, or anything else that is needed in the app. Values are fetched lazily and can depend on other values in this container.
There is no namespacing/hierarchy.
In general, you should not create instances of this class, but you may need to access it via Brut.container in order to obtain configuration values or set your own.
Instance Method Summary collapse
-
#fetch(name) ⇒ Object
Fetch the value given a name.
-
#initialize ⇒ Container
constructor
A new instance of Container.
-
#method_missing(sym, *args, &block) ⇒ Object
Provides method-like access to configured values.
-
#override(name, value = :use_block) {|*any| ... } ⇒ Object
Called by your app to override an existing value.
-
#reload ⇒ Object
-
#respond_to_missing?(name, include_private = false) ⇒ true|false
Required for good decorum when overriding #method_missing.
-
#store(name, type, description, value = :use_block, allow_app_override: false, allow_nil: false) {|*any| ... } ⇒ Object
Store a named value for later.
-
#store_ensured_path(name, description, value = :use_block) {|*any| ... } ⇒ Object
Store a value that represents a path that will be created if it doesn't exist.
-
#store_required_path(name, description, value = :use_block) {|*any| ... } ⇒ Object
Store a value that represents a path that must exist.
Constructor Details
#initialize ⇒ Container
Returns a new instance of Container.
28 29 30 |
# File 'lib/brut/framework/container.rb', line 28 def initialize @container = {} end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(sym, *args, &block) ⇒ Object
Provides method-like access to configured values. Only configured values will respond and only if the accessor method is called without parameters and without a block. See #fetch.
165 166 167 168 169 170 171 |
# File 'lib/brut/framework/container.rb', line 165 def method_missing(sym,*args,&block) if args.length == 0 && block.nil? && self.respond_to_missing?(sym) fetch(sym.to_s) else super.method_missing(sym,*args,&block) end end |
Instance Method Details
#fetch(name) ⇒ Object
Fetch the value given a name. For lazily-defined values, this will call all necessary blocks needed to determine the value. Thus, any number of other blocks could be called, depending on what values are needed.
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/brut/framework/container.rb', line 191 def fetch(name) name = name.to_s # TODO: Provide a cleanr impl and better error checking if things go wrong x = @container.fetch(name) has_value = x.key?(:value) if has_value handle_path_values(name,x) return x[:value] end deriver = x[:derive_with] if deriver.nil? raise "Something is seriously wrong. '#{name}' was stored in container without a static value, but also without a derive_with key" end parameters = deriver.parameters(lambda: true) args = parameters.map { |param_description| param_description[1] }.map { |name_of_dependent_object| self.send(name_of_dependent_object) } value = deriver.(*args) if x[:type] == :boolean value = !!value end x[:value] = value if x[:value].nil? if !x[:allow_nil] raise "Something is wrong: #{name} had no value" end end handle_path_values(name,x) x[:value] end |
#override(name, value = :use_block) {|*any| ... } ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/brut/framework/container.rb', line 105 def override(name,value=:use_block,&block) name = name.to_s if !@container[name] raise ArgumentError,"#{name} has not been specified so you cannot override it" end if !@container[name][:allow_app_override] raise ArgumentError,"#{name} does not allow the app to override it" end if value == :use_block @container[name][:derive_with] = block @container[name].delete(:value) else @container[name][:value] = value @container[name].delete(:derive_with) end end |
#reload ⇒ Object
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/brut/framework/container.rb', line 224 def reload @container.each do |name, contained_value| if contained_value.key?(:value) && contained_value[:type].to_s == "Class" if contained_value.key?(:derive_with) contained_value.delete(:value) else klass = contained_value[:value] new_klass = klass.name.split(/::/).reduce(Module) { |mod,part| mod.const_get(part) } contained_value[:value] = new_klass end end end end |
#respond_to_missing?(name, include_private = false) ⇒ true|false
Required for good decorum when overriding #method_missing.
178 179 180 |
# File 'lib/brut/framework/container.rb', line 178 def respond_to_missing?(name,include_private=false) @container.key?(name.to_s) end |
#store(name, type, description, value = :use_block, allow_app_override: false, allow_nil: false) {|*any| ... } ⇒ Object
Store a named value for later. You can use this to store static values, or dynamic values that require the values of other stored values.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/brut/framework/container.rb', line 67 def store(name,type,description,value=:use_block,allow_app_override: false,allow_nil: false,&block) # TODO: Check that value / block is used properly name = name.to_s if type == "boolean" type = :boolean end if type == :boolean if name !~ /\?$/ raise ArgumentError, "#{name} is a boolean so must end with a question mark" end end self.validate_name!(name:,type:,allow_app_override:) if value == :use_block derive_with = block @container[name] = { derive_with: derive_with } else if type == :boolean value = !!value end @container[name] = { value: value } end @container[name][:description] = description @container[name][:type] = type @container[name][:allow_app_override] = allow_app_override @container[name][:allow_nil] = allow_nil self end |
#store_ensured_path(name, description, value = :use_block) {|*any| ... } ⇒ Object
Store a value that represents a path that will be created if it doesn't exist.
The value will be assumed to be a Pathname
and the name
must end in _dir
or _file
.
This is preferred over #store_required_path so that you don't have to have a bunch of .keep
files hanging around
just for your version control system. The path will be created as a directory whenever it is first accessed.
153 154 155 156 157 |
# File 'lib/brut/framework/container.rb', line 153 def store_ensured_path(name,description,value=:use_block,&block) self.store(name,Pathname,description,value,&block) @container[name][:ensured_path] = true self end |
#store_required_path(name, description, value = :use_block) {|*any| ... } ⇒ Object
Store a value that represents a path that must exist. The value will
be assumed to be a Pathname
and the name
must end in _dir
or _file
.
Note that the value's existence is not checked until it is requested. When it is,
an exception will be raised if it does not exist.
134 135 136 137 138 |
# File 'lib/brut/framework/container.rb', line 134 def store_required_path(name,description,value=:use_block,&block) self.store(name,Pathname,description,value,&block) @container[name][:required_path] = true self end |