Class: SmartName

Inherits:
Object show all
Includes:
ActiveSupport::Configurable
Defined in:
lib/smart_name.rb

Constant Summary collapse

RUBYENCODING =
RUBY_VERSION !~ /^1\.8/
OK4KEY_RE =
RUBYENCODING ? '\p{Word}\*' : '\w\*'
JOINT_RE =
Regexp.escape joint
@@name2nameobject =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(str) ⇒ SmartName

Returns a new instance of SmartName.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/smart_name.rb', line 46

def initialize str
  @s = str.to_s.strip
  @s = @s.encode('UTF-8') if RUBYENCODING
  @key = if @s.index(self.class.joint)
           @parts = @s.split(/\s*#{JOINT_RE}\s*/)
           @parts << '' if @s[-1, 1] == self.class.joint
           @simple = false
           @parts.map { |p| p.to_name.key } * self.class.joint
         else
           @parts = [str]
           @simple = true
           str.empty? ? '' : simple_key
         end
  @@name2nameobject[str] = self
end

Instance Attribute Details

#keyObject (readonly)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ INSTANCE ~~~~~~~~~~~~~~~~~~~~~~~~~



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

def key
  @key
end

#partsObject (readonly)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ INSTANCE ~~~~~~~~~~~~~~~~~~~~~~~~~



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

def parts
  @parts
end

#sObject (readonly) Also known as: to_s

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ INSTANCE ~~~~~~~~~~~~~~~~~~~~~~~~~



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

def s
  @s
end

#simpleObject (readonly) Also known as: simple?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ INSTANCE ~~~~~~~~~~~~~~~~~~~~~~~~~



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

def simple
  @simple
end

Class Method Details

.banned_reObject



35
36
37
# File 'lib/smart_name.rb', line 35

def banned_re
  %r{#{ (['['] + banned_array << joint) * '\\' + ']' }}
end

.new(obj) ⇒ Object



25
26
27
28
29
30
31
32
33
# File 'lib/smart_name.rb', line 25

def new obj
  return obj if obj.is_a? self.class
  str = obj.is_a?(Array) ? obj * joint : obj.to_s
  if (known_name = @@name2nameobject[str])
    known_name
  else
    super str.strip
  end
end

.substitute!(str, hash) ⇒ Object

HACK. This doesn’t belong here. shouldn’t it use inclusions???



280
281
282
283
284
285
286
287
# File 'lib/smart_name.rb', line 280

def self.substitute! str, hash
  hash.keys.each do |var|
    str.gsub! var_re do |x|
      hash[var.to_sym]
    end
  end
  str
end

Instance Method Details

#==(other) ⇒ Object



89
90
91
92
93
94
95
96
97
# File 'lib/smart_name.rb', line 89

def == other
  other_key =
    case
    when other.respond_to?(:key)     then other.key
    when other.respond_to?(:to_name) then other.to_name.key
    else                                  other.to_s
    end
  other_key == key
end

#blank?Boolean Also known as: empty?

Returns:

  • (Boolean)


74
75
76
# File 'lib/smart_name.rb', line 74

def blank?
  s.blank?
end

#decodedObject



121
122
123
# File 'lib/smart_name.rb', line 121

def decoded
  @decoded ||= s.index('&') ? HTMLEntities.new.decode(s) : s
end

#inspectObject



85
86
87
# File 'lib/smart_name.rb', line 85

def inspect
  "<#{self.class.name} key=#{key}[#{self}]>"
end

#junction?Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/smart_name.rb', line 128

def junction?
  !simple?
end

#leftObject



132
133
134
# File 'lib/smart_name.rb', line 132

def left
  @left ||= simple? ? nil : parts[0..-2] * self.class.joint
end

#left_nameObject



140
141
142
# File 'lib/smart_name.rb', line 140

def left_name
  @left_name ||= left && self.class.new(left)
end

#lengthObject



66
67
68
# File 'lib/smart_name.rb', line 66

def length
  parts.length
end

#nth_left(n) ⇒ Object



245
246
247
248
# File 'lib/smart_name.rb', line 245

def nth_left n
  # 1 = left; 2= left of left; 3 = left of left of left....
  (n >= length ? parts[0] : parts[0..-n - 1]).to_name
end

#part_namesObject



167
168
169
# File 'lib/smart_name.rb', line 167

def part_names
  @part_names ||= parts.map(&:to_name)
end

#piece_namesObject



171
172
173
# File 'lib/smart_name.rb', line 171

def piece_names
  @piece_names ||= pieces.map(&:to_name)
end

#piecesObject



175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/smart_name.rb', line 175

def pieces
  @pieces ||=
    if simple?
      [self]
    else
      junction_pieces = []
      parts[1..-1].inject parts[0] do |left, right|
        piece = [left, right] * self.class.joint
        junction_pieces << piece
        piece
      end
      parts + junction_pieces
    end
end

#replace_part(oldpart, newpart) ⇒ Object

~~~~~~~~~~~~~~~~~~~~ MISC ~~~~~~~~~~~~~~~~~~~~



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/smart_name.rb', line 252

def replace_part oldpart, newpart
  oldpart = oldpart.to_name
  newpart = newpart.to_name
  if oldpart.simple?
    if simple?
      self == oldpart ? newpart : self
    else
      parts.map do |p|
        oldpart == p ? newpart.to_s : p
      end.to_name
    end
  elsif simple?
    self
  else
    if oldpart == parts[0, oldpart.length]
      if length == oldpart.length
        newpart
      else
        (newpart.parts + parts[oldpart.length..-1]).to_name
      end
    else
      self
    end
  end
end

#rightObject



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

def right
  @right ||= simple? ? nil : parts[-1]
end

#right_nameObject



144
145
146
# File 'lib/smart_name.rb', line 144

def right_name
  @right_name ||= right && self.class.new(right)
end

#safe_keyObject



117
118
119
# File 'lib/smart_name.rb', line 117

def safe_key
  @safe_key ||= key.tr('*', 'X').tr self.class.joint, '-'
end

#simple_keyObject

~~~~~~~~~~~~~~~~~~~ VARIANTS ~~~~~~~~~~~~~~~~~~~



101
102
103
104
105
106
107
108
# File 'lib/smart_name.rb', line 101

def simple_key
  decoded
    .underscore
    .gsub(/[^#{OK4KEY_RE}]+/, '_')
    .split(/_+/)
    .reject(&:empty?)
    .map(&self.class.uninflect) * '_'
end

#sizeObject



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

def size
  to_s.size
end

#tagObject



155
156
157
# File 'lib/smart_name.rb', line 155

def tag
  @tag ||= simple? ? s : right
end

#tag_nameObject



163
164
165
# File 'lib/smart_name.rb', line 163

def tag_name
  @tag_name ||= simple? ? self : right_name
end

#to_absolute(context, args = {}) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/smart_name.rb', line 209

def to_absolute context, args={}
  context = context.to_name
  parts.map do |part|
    new_part =
      case part
      when /^_user$/i
        name_proc = self.class.session
        name_proc ? name_proc.call : part
      when /^_main$/i            then self.class.params[:main_name]
      when /^(_self|_whole|_)$/i then context.s
      when /^_left$/i            then context.trunk
        # note - inconsistent use of left v. trunk
      when /^_right$/i           then context.tag
      when /^_(\d+)$/i
        pos = $~[1].to_i
        pos = context.length if pos > context.length
        context.parts[pos - 1]
      when /^_(L*)(R?)$/i
        l_s, r_s = $~[1].size, !$~[2].empty?
        l_part = context.nth_left l_s
        r_s ? l_part.tag : l_part.s
      # when /^_/
      #   custom = args[:params] ? args[:params][part] : nil
      #   custom ? CGI.escapeHTML(custom) : part
      # why are we escaping HTML here?
      else
        part
      end.to_s.strip
    new_part.empty? ? context.to_s : new_part
  end * self.class.joint
end

#to_absolute_name(*args) ⇒ Object



241
242
243
# File 'lib/smart_name.rb', line 241

def to_absolute_name *args
  self.class.new to_absolute(*args)
end

#to_nameObject



62
63
64
# File 'lib/smart_name.rb', line 62

def to_name
  self
end

#to_show(*ignore) ⇒ Object

~~~~~~~~~~~~~~~~~~~~ SHOW / ABSOLUTE ~~~~~~~~~~~~~~~~~~~~



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/smart_name.rb', line 192

def to_show *ignore
  ignore.map!(&:to_name)

  show_parts = parts.map do |part|
    reject = (part.empty? || (part =~ /^_/) || ignore.member?(part.to_name))
    reject ? nil : part
  end

  show_name = show_parts.compact.to_name.s

  case
  when show_parts.compact.empty? then  self
  when show_parts[0].nil?        then  self.class.joint + show_name
  else show_name
  end
end

#trunkObject

Note that all names have a trunk and tag, but only junctions have left and right



151
152
153
# File 'lib/smart_name.rb', line 151

def trunk
  @trunk ||= simple? ? s : left
end

#trunk_nameObject



159
160
161
# File 'lib/smart_name.rb', line 159

def trunk_name
  @trunk_name ||= simple? ? self : left_name
end

#url_keyObject



110
111
112
113
114
115
# File 'lib/smart_name.rb', line 110

def url_key
  @url_key ||= part_names.map do |part_name|
    stripped = part_name.decoded.gsub(/[^#{OK4KEY_RE}]+/, ' ').strip
    stripped.gsub(/[\s\_]+/, '_')
  end * self.class.joint
end

#valid?Boolean

Returns:

  • (Boolean)


79
80
81
82
83
# File 'lib/smart_name.rb', line 79

def valid?
  !parts.find do |pt|
    pt.match self.class.banned_re
  end
end