Class: Nomen::Item

Inherits:
Object
  • Object
show all
Defined in:
lib/nomen/item.rb

Overview

An item of a nomenclature is the core data.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(nomenclature, name, options = {}) ⇒ Item

New item


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/nomen/item.rb', line 9

def initialize(nomenclature, name, options = {})
  @nomenclature = nomenclature
  @name = name.to_s
  @left, @right = @nomenclature.new_boundaries
  @depth = 0
  parent = options.delete(:parent)
  if parent.is_a?(Symbol) || parent.is_a?(String)
    @parent_name = parent.to_s
  else
    self.parent = parent
  end
  @attributes = {}.with_indifferent_access
  options.each do |k, v|
    set(k, v)
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args) ⇒ Object

Returns property descriptor


265
266
267
268
# File 'lib/nomen/item.rb', line 265

def method_missing(method_name, *args)
  return property(method_name) if has_property?(method_name)
  super
end

Instance Attribute Details

#aliasesObject (readonly)

Returns the value of attribute aliases


4
5
6
# File 'lib/nomen/item.rb', line 4

def aliases
  @aliases
end

#attributesObject Also known as: properties

Returns the value of attribute attributes


5
6
7
# File 'lib/nomen/item.rb', line 5

def attributes
  @attributes
end

#depthObject (readonly)

Returns the value of attribute depth


4
5
6
# File 'lib/nomen/item.rb', line 4

def depth
  @depth
end

#leftObject (readonly)

Returns the value of attribute left


4
5
6
# File 'lib/nomen/item.rb', line 4

def left
  @left
end

#nameObject

Returns the value of attribute name


5
6
7
# File 'lib/nomen/item.rb', line 5

def name
  @name
end

#nomenclatureObject (readonly)

Returns the value of attribute nomenclature


4
5
6
# File 'lib/nomen/item.rb', line 4

def nomenclature
  @nomenclature
end

#parent_nameObject

Returns the value of attribute parent_name


4
5
6
# File 'lib/nomen/item.rb', line 4

def parent_name
  @parent_name
end

#rightObject (readonly)

Returns the value of attribute right


4
5
6
# File 'lib/nomen/item.rb', line 4

def right
  @right
end

Instance Method Details

#<(other) ⇒ Object


179
180
181
182
# File 'lib/nomen/item.rb', line 179

def <(other)
  other = item_for_comparison(other)
  (other.left < @left && @right < other.right)
end

#<=(other) ⇒ Object


189
190
191
192
# File 'lib/nomen/item.rb', line 189

def <=(other)
  other = item_for_comparison(other)
  (other.left <= @left && @right <= other.right)
end

#<=>(other) ⇒ Object


174
175
176
177
# File 'lib/nomen/item.rb', line 174

def <=>(other)
  other = item_for_comparison(other)
  nomenclature.name <=> other.nomenclature.name && name <=> other.name
end

#==(other) ⇒ Object


169
170
171
172
# File 'lib/nomen/item.rb', line 169

def ==(other)
  other = item_for_comparison(other)
  nomenclature == other.nomenclature && name == other.name
end

#>(other) ⇒ Object


184
185
186
187
# File 'lib/nomen/item.rb', line 184

def >(other)
  other = item_for_comparison(other)
  (@left < other.left && other.right < @right)
end

#>=(other) ⇒ Object


194
195
196
197
# File 'lib/nomen/item.rb', line 194

def >=(other)
  other = item_for_comparison(other)
  (@left <= other.left && other.right <= @right)
end

#children(options = {}) ⇒ Object

Returns children recursively by default


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
# File 'lib/nomen/item.rb', line 84

def children(options = {})
  if options[:index].is_a?(FalseClass)
    if options[:recursively].is_a?(FalseClass)
      return nomenclature.list.select do |item|
        (item.parent == self)
      end
    else
      return children(index: false, recursive: false).each_with_object([]) do |item, list|
        list << item
        list += item.children(index: false, recursive: true)
        list
      end
    end
  else
    if options[:recursively].is_a?(FalseClass)
      return nomenclature.list.select do |item|
        @left < item.left && item.right < @right && item.depth == @depth + 1
      end
    else
      # @children ||=
      return nomenclature.list.select do |item|
        @left < item.left && item.right < @right
      end
    end
  end
end

#degree_of_kinship_with(other) ⇒ Object


65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/nomen/item.rb', line 65

def degree_of_kinship_with(other)
  other_item = item_for_comparison(other)
  a = self_and_parents.reverse
  b = other_item.self_and_parents.reverse
  return nil if a.first != b.first
  common_lineage = 0
  a.size.times do |index|
    break if a[index].nil? || b[index].nil? || a[index] != b[index]
    common_lineage += 1
  end
  a.size + b.size - 2 * common_lineage
end

#has_property?(name) ⇒ Boolean

Checks if item has property with given name

Returns:

  • (Boolean)

260
261
262
# File 'lib/nomen/item.rb', line 260

def has_property?(name)
  !@nomenclature.properties[name].nil?
end

#human_name(options = {}) ⇒ Object Also known as: humanize, localize

Return human name of item


158
159
160
# File 'lib/nomen/item.rb', line 158

def human_name(options = {})
  "nomenclatures.#{nomenclature.name}.items.#{name}".t(options.merge(default: ["items.#{name}".to_sym, "enumerize.#{nomenclature.name}.#{name}".to_sym, "labels.#{name}".to_sym, name.humanize]))
end

#human_notion_name(notion_name, options = {}) ⇒ Object


165
166
167
# File 'lib/nomen/item.rb', line 165

def human_notion_name(notion_name, options = {})
  "nomenclatures.#{nomenclature.name}.notions.#{notion_name}.#{name}".t(options.merge(default: ["labels.#{name}".to_sym]))
end

#include?(other) ⇒ Boolean

Returns true if the given item name match the current item or its children

Returns:

  • (Boolean)

153
154
155
# File 'lib/nomen/item.rb', line 153

def include?(other)
  self >= other
end

#inspectObject


199
200
201
# File 'lib/nomen/item.rb', line 199

def inspect
  "#{@nomenclature.name}-#{@name}(#{@left}-#{@right})"
end

#original_nomenclature_nameObject


78
79
80
81
# File 'lib/nomen/item.rb', line 78

def original_nomenclature_name
  return parent.name.to_sym unless root?
  nil
end

#parentObject


61
62
63
# File 'lib/nomen/item.rb', line 61

def parent
  @parent ||= @nomenclature.find(@parent_name)
end

#parent=(item) ⇒ Object


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/nomen/item.rb', line 30

def parent=(item)
  old_parent_name = @parent_name
  if item.nil?
    @parent = nil
    @parent_name = nil
  else
    if item.is_a?(Symbol) || item.is_a?(String)
      item = nomenclature.find!(item.to_s)
    end
    if item.nomenclature != nomenclature
      raise 'Item must come from same nomenclature'
    end
    if item.parents.include?(self) || item == self
      raise 'Circular dependency. Item can be parent of itself.'
    end
    @parent = item
    @parent_name = @parent.name.to_s
  end
  @nomenclature.rebuild_tree! if old_parent_name != @parent_name
end

#parent?Boolean

Returns:

  • (Boolean)

57
58
59
# File 'lib/nomen/item.rb', line 57

def parent?
  parent.present?
end

#parentsObject

Returns direct parents from the closest to the farthest


116
117
118
# File 'lib/nomen/item.rb', line 116

def parents
  @parents ||= (parent.nil? ? [] : [parent] + parent.parents)
end

#property(name) ⇒ Object

Returns property value


229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/nomen/item.rb', line 229

def property(name)
  property = @nomenclature.properties[name]
  value = @attributes[name]
  if property
    if value.nil? && property.fallbacks
      property.fallbacks.each do |fallback|
        value ||= @attributes[fallback]
        break if value
      end
    end
    value ||= cast_property(name, property.default) if property.default
  end
  value
end

#rebuild_tree(left = 0, depth = 0) ⇒ Object

Computes left/right value for nested set Returns right index


142
143
144
145
146
147
148
149
150
# File 'lib/nomen/item.rb', line 142

def rebuild_tree(left = 0, depth = 0)
  @depth = depth
  @left = left
  @right = @left + 1
  children(index: false, recursively: false).each do |child|
    @right = child.rebuild_tree(@right, @depth + 1) + 1
  end
  @right
end

#rebuild_tree!Object

Computes left/right value for nested set Returns right index


136
137
138
# File 'lib/nomen/item.rb', line 136

def rebuild_tree!
  @nomenclature.forest_right = rebuild_tree(@nomenclature.forest_right + 1)
end

#rise(&block) ⇒ Object


128
129
130
131
132
# File 'lib/nomen/item.rb', line 128

def rise(&block)
  result = yield(self)
  return result if result
  parent ? parent.rise(&block) : nil
end

#rootObject


111
112
113
# File 'lib/nomen/item.rb', line 111

def root
  parent? ? parent.root : self
end

#root?Boolean

Returns:

  • (Boolean)

26
27
28
# File 'lib/nomen/item.rb', line 26

def root?
  !parent
end

#selection(name) ⇒ Object


244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/nomen/item.rb', line 244

def selection(name)
  property = @nomenclature.properties[name]
  if property.list?
    return property(name).collect do |i|
      ["nomenclatures.#{@nomenclature.name}.item_lists.#{self.name}.#{name}.#{i}".t, i]
    end
  elsif property.nomenclature?
    return Nomen[property(name)].list.collect do |i|
      [i.human_name, i.name]
    end
  else
    raise StandardError, 'Cannot call selection for a non-list property'
  end
end

#self_and_children(options = {}) ⇒ Object


120
121
122
# File 'lib/nomen/item.rb', line 120

def self_and_children(options = {})
  [self] + children(options)
end

#self_and_parentsObject


124
125
126
# File 'lib/nomen/item.rb', line 124

def self_and_parents
  [self] + parents
end

#set(name, value) ⇒ Object


270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/nomen/item.rb', line 270

def set(name, value)
  raise "Invalid property: #{name.inspect}" if [:name, :parent].include?(name.to_sym)
  # # TODO: check format
  # if property = nomenclature.properties[name]
  #   value ||= [] if property.list?
  # end
  if value.nil?
    @attributes.delete(name)
  else
    @attributes[name] = value
  end
end

#to_xml_attrsObject


211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/nomen/item.rb', line 211

def to_xml_attrs
  attrs = {}
  attrs[:name] = name
  attrs[:parent] = @parent_name if parent?
  properties.each do |pname, pvalue|
    if p = nomenclature.properties[pname.to_s]
      if p.type == :decimal
        pvalue = pvalue.to_s.to_f
      elsif p.list?
        pvalue = pvalue.join(', ')
      end
    end
    attrs[pname] = pvalue.to_s
  end
  attrs
end

#tree(depth = 0) ⇒ Object


203
204
205
206
207
208
209
# File 'lib/nomen/item.rb', line 203

def tree(depth = 0)
  text = "#{left.to_s.rjust(4)}-#{right.to_s.ljust(4)} #{'  ' * depth}#{@name}:\n"
  text << children(index: false, recursively: false).collect do |c|
    c.tree(depth + 1)
  end.join("\n")
  text
end