Class: NsOptions::Namespace

Inherits:
Object
  • Object
show all
Defined in:
lib/ns-options/namespace.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, parent = nil, &block) ⇒ Namespace

Every namespace tracks a metaclass to allow for individual reader/writers for their options, without any collisions. Since every namespace is of the same class, defining option reader and writer methods directly on the class would make multiple namespaces with different options impossible.



10
11
12
13
14
# File 'lib/ns-options/namespace.rb', line 10

def initialize(key, parent = nil, &block)
  self.metaclass = (class << self; self; end)
  self.options = NsOptions::Options.new(key, parent)
  self.define(&block)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

There are a number of cases we want to watch for:

  1. A reader of a ‘known’ option. This case is for an option that’s been defined for an ancestor of this namespace but not directly for this namespace. In this case we fetch the options definition and use it to define the option directly for this namespace.

  2. TODO

  3. A writer of a ‘known’ option. This case is similar to the above, but instead we are wanting to write a value. We need to fetch the option definition, define it and then we write the option as we normally would.

  4. A dynamic writer. The option is not ‘known’ to the namespace, so we use the value and it’s class to define the option for this namespace. Then we just use the writer as we normally would.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/ns-options/namespace.rb', line 130

def method_missing(method, *args, &block)
  option_name = method.to_s.gsub("=", "")
  value = args.size == 1 ? args[0] : args
  if args.empty? && self.respond_to?(option_name)
    option = NsOptions::Helper.find_and_define_option(self, option_name)
    self.send(option.name)
  elsif args.empty? && (namespace = self.options.get_namespace(option_name))
    NsOptions::Helper.find_and_define_namespace(self, option_name)
    self.send(option_name)
  elsif !args.empty? && self.respond_to?(option_name)
    option = NsOptions::Helper.find_and_define_option(self, option_name)
    self.send("#{option.name}=", value)
  elsif !args.empty?
    option = self.option(option_name)
    self.send("#{option.name}=", value)
  else
    super
  end
end

Instance Attribute Details

#metaclassObject

Returns the value of attribute metaclass.



4
5
6
# File 'lib/ns-options/namespace.rb', line 4

def metaclass
  @metaclass
end

#optionsObject

Returns the value of attribute options.



4
5
6
# File 'lib/ns-options/namespace.rb', line 4

def options
  @options
end

Instance Method Details

#apply(option_values = {}) ⇒ Object

The opposite of #to_hash. Takes a hash representation of options and namespaces and mass assigns option values.



68
69
70
71
72
73
74
75
76
77
# File 'lib/ns-options/namespace.rb', line 68

def apply(option_values = {})
  option_values.each do |name, value|
    namespace = self.options.namespaces[name]
    if self.options[name] || !namespace
      self.send("#{name}=", value)
    elsif namespace && value.kind_of?(Hash)
      namespace.apply(value)
    end
  end
end

#define(&block) ⇒ Object

The define method is provided for convenience and commonization. The internal system uses it to commonly use a block with a namespace. The method can be used externally when a namespace is created separately from where options are added/set on it. For example:

parent_namespace.namespace(:specific)

parent_namespace.specific.define do

option :root

end

Will define a new namespace under the parent namespace and then will later on add options to it.



110
111
112
113
114
115
116
117
# File 'lib/ns-options/namespace.rb', line 110

def define(&block)
  if block && block.arity > 0
    yield self
  elsif block
    self.instance_eval(&block)
  end
  self
end

#eachObject

allow for iterating over the key/values of a namespace this uses #to_hash so you won’t get option/namespace objs for the values



94
95
96
# File 'lib/ns-options/namespace.rb', line 94

def each
  self.to_hash.each { |k,v| yield k,v if block_given? }
end

#inspect(*args) ⇒ Object



154
155
156
# File 'lib/ns-options/namespace.rb', line 154

def inspect(*args)
  "#<#{self.class}:#{'0x%x' % (self.object_id << 1)}:#{self.options.key} #{self.to_hash.inspect}>"
end

#namespace(name, key = nil, &block) ⇒ Object Also known as: ns

Define a namespace under this namespace. Firstly, a new key is constructured from this current namespace’s key and the name for the new namespace. The namespace is then added to the options collection. Finally a reader method is defined for accessing the namespace. With the following:

parent_namespace.namespace(:specific) do

option :root

end

you will get a reader for the namespace:

parent_namespace.specific # => returns the namespace parent_namespace.specific.root = “something” # => options are accessed in the same way

The defined namespaces is returned as well.



57
58
59
60
61
62
63
# File 'lib/ns-options/namespace.rb', line 57

def namespace(name, key = nil, &block)
  key = "#{self.options.key}:#{(key || name)}"
  NsOptions::Helper.advisor(self).is_this_sub_namespace_ok?(name, caller)
  namespace = self.options.add_namespace(name, key, self, &block)
  NsOptions::Helper.define_namespace_methods(self, name)
  namespace
end

#option(*args) ⇒ Object Also known as: opt

Define an option for this namespace. Add the option to the namespace’s options collection and then define accessors for the option. With the following:

namespace.option(:root, String, { :some_option => true })

you will get accessors for root:

namespace.root = “something” # set’s the root option to ‘something’ namespace.root # => “something” namespace.root(“something else”) # set’s the root option to ‘something-else`

The defined option is returned as well.



34
35
36
37
38
39
# File 'lib/ns-options/namespace.rb', line 34

def option(*args)
  NsOptions::Helper.advisor(self).is_this_option_ok?(args[0], caller)
  option = self.options.add(*args)
  NsOptions::Helper.define_option_methods(self, option)
  option
end

#required_set?Boolean Also known as: valid?

This is a helper to check if options that were defined as :required have been set.

Returns:



17
18
19
# File 'lib/ns-options/namespace.rb', line 17

def required_set?
  self.options.required_set?
end

#respond_to?(method) ⇒ Boolean

Returns:



150
151
152
# File 'lib/ns-options/namespace.rb', line 150

def respond_to?(method)
  super || self.options.is_defined?(method.to_s.gsub("=", ""))
end

#to_hashObject

return a hash representation of the namespace use symbols for the hash



81
82
83
84
85
86
87
88
89
90
# File 'lib/ns-options/namespace.rb', line 81

def to_hash
  Hash.new.tap do |out|
    self.options.each do |name, opt|
      out[name.to_sym] = opt.value
    end
    self.options.namespaces.each do |name, value|
      out[name.to_sym] = value.to_hash
    end
  end
end