Class: Settings::Cursor

Inherits:
DslBuilder
  • Object
show all
Defined in:
lib/iron/settings/cursor.rb

Overview

Cursors handle navigating the settings hierarchy built by our Builder class, allowing getting and setting entry values and inspecting the hierarchy itself.

Instance Method Summary collapse

Constructor Details

#initialize(group, values, context = nil) ⇒ Cursor

Start up our cursor bound to a given group in the settings hierarchy, with the value store holding the values for the current context.



9
10
11
12
13
# File 'lib/iron/settings/cursor.rb', line 9

def initialize(group, values, context = nil)
  @group = group
  @values = values
  @context = context
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

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

Look for the next item from our current group pointer, returning a new cursor if the item is a sub-group, or the value of the requested entry if the item is a leaf in the hierarchy tree.



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
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/iron/settings/cursor.rb', line 94

def method_missing(method, *args, &block)
  method = method.to_s
  query = method.ends_with?('?')
  assignment = method.ends_with?('=')
  method.gsub!(/[=\?]+/,'')
  
  # Look up the item
  item = @group.find_item(method)
  if item.nil?
    # Unknown item name, whoops.
    if query
      # Querying for existence of key is fine if it's missing
      return false
    else
      # Setting or getting, GTFO
      raise RuntimeError.new("Unknown settings group or entry '#{method}' for settings path #{@group.key}")
    end
    
  elsif item.group?
    if query
      # Yes, this group exists
      return true
    else
      # Got asked for another group, so create a new cursor and do the right thing(tm)
      cursor = Settings::Cursor.new(item, @values)
      DslProxy::exec(cursor, &block) if block
      return cursor
    end
    
  elsif item.entry?
    if query
      # Return true if the given item has a non-nil value
      return !item_value(item).nil?
    else
      if args.empty?
        # No args means return the current value (or default if none)
        return item_value(item)
      else
        # With args, we set the current value of the item (if it parses correctly)
        val = Settings.parse(args.first, item.type)
        @values.set_value(item.key, val)
        return args.first
      end
    end
  end
end

Instance Method Details

#[](key, &block) ⇒ Object

Array-like access to the entry value at the specified key



69
70
71
72
73
74
75
76
77
78
79
# File 'lib/iron/settings/cursor.rb', line 69

def [](key, &block)
  item = find_item(key)
  if item.group?
    # Got asked for another group, so create a new cursor and do the right thing(tm)
    cursor = Settings::Cursor.new(item, @values)
    DslProxy::exec(cursor, &block) if block
    cursor
  else
    item_value(item)
  end
end

#[]=(key, val) ⇒ Object

Array-like setter for entry values using the specified key



82
83
84
85
86
87
88
# File 'lib/iron/settings/cursor.rb', line 82

def []=(key, val)
  item = find_item(key)
  if item
    @values.set_value(item.key, Settings.parse(val, item.type))
  end
  val
end

#entry_keys(include_all = true) ⇒ Object

Returns all entry keys at the cursor’s current position, and optionally including all child keys. If the cursor is at a sub-group node, keys will be relative to that node.



24
25
26
27
28
29
30
# File 'lib/iron/settings/cursor.rb', line 24

def entry_keys(include_all = true)
  keys = @group.entries(include_all).collect {|e| e.key }
  unless @group.key.blank?
    keys.collect! {|k| k.gsub(@group.key + '.', '') }
  end
  keys
end

#entry_values(include_all = true) ⇒ Object

Returns a hash of all entry keys to their values at the cursor’s current position, and optionally including all child keys. If the cursor is at a sub-group node, keys will be relative to that node.



35
36
37
38
# File 'lib/iron/settings/cursor.rb', line 35

def entry_values(include_all = true)
  keys = entry_keys(include_all)
  keys.convert_to_hash {|k| item_value(find_item(k)) }
end

#eval_in_context(text) ⇒ Object

:nodoc:



176
177
178
179
180
# File 'lib/iron/settings/cursor.rb', line 176

def eval_in_context(text) # :nodoc:
  proc = Proc.new {}
  binding = proc.binding
  eval(text, binding)
end

#find_entries(include_all = true) ⇒ Object

Return Settings::Entry items for entries at this cursor level and optionally below it



64
65
66
# File 'lib/iron/settings/cursor.rb', line 64

def find_entries(include_all = true)
  @group.entries(include_all)
end

#find_item(key) ⇒ Object

Finds the item (group or entry) in the hierarchy matching the provided relative key. Raises a RuntimeError on unknown keys.



51
52
53
54
55
56
57
58
59
60
61
# File 'lib/iron/settings/cursor.rb', line 51

def find_item(key)
  item = @group
  key = key.to_s
  parts = key.split(/\./)
  until parts.empty?
    item_key = parts.shift
    item = item.find_item(item_key)
    raise RuntimeError.new("Unknown settings group or entry '#{item_key}' in settings path #{[@group.key,key].list_join('.')}") if item.nil?
  end
  item
end

#group_keys(include_all = false) ⇒ Object

Returns all group keys



41
42
43
44
45
46
47
# File 'lib/iron/settings/cursor.rb', line 41

def group_keys(include_all = false)
  keys = @group.entries(include_all).collect {|e| e.key }
  unless @group.key.blank?
    keys.collect! {|k| k.gsub(@group.key + '.', '') }
  end
  keys
end

#item_default_value(item) ⇒ Object

Calculates the default value for an entry, handling callable defaults.



163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/iron/settings/cursor.rb', line 163

def item_default_value(item)
  return nil if item.group? || item.default.nil?
  if item.default.respond_to?(:call)
    # Callable default, call in context of a root cursor, yielding our context (generally a
    # model instance) to the block.
    val = DslProxy.exec(Cursor.new(root, @values), @context, &(item.default))
    val = Settings.parse(val, item.type)
  else
    val = item.default
  end
  Settings.restore(val, item.type)
end

#item_has_value?(item) ⇒ Boolean

When true, has non-default value set for the given entry

Returns:

  • (Boolean)


149
150
151
152
# File 'lib/iron/settings/cursor.rb', line 149

def item_has_value?(item)
  return false if item.group?
  @values.has_value?(item.key)
end

#item_value(item) ⇒ Object

Calculates the value of the given entry item given the current value store and item default value.



156
157
158
159
160
# File 'lib/iron/settings/cursor.rb', line 156

def item_value(item)
  return item_default_value(item) unless item_has_value?(item)
  val = @values.get_value(item.key)
  Settings.restore(val, item.type)
end

#respond_to_missing?(method, include_private = false) ⇒ Boolean

Counterpart to #method_missing

Returns:

  • (Boolean)


142
143
144
145
146
# File 'lib/iron/settings/cursor.rb', line 142

def respond_to_missing?(method, include_private = false)
  method = method.to_s.gsub(/[=\?]+/,'')
  item = @group.find_item(method)
  return !item.nil?
end

#rootObject

Provides access to the root of the hierarchy, generally not useful during operations… :-)



17
18
19
# File 'lib/iron/settings/cursor.rb', line 17

def root
  @group.root
end