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.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/smart_name.rb', line 50

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 ~~~~~~~~~~~~~~~~~~~~~~~~~



47
48
49
# File 'lib/smart_name.rb', line 47

def key
  @key
end

#partsObject (readonly)

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



47
48
49
# File 'lib/smart_name.rb', line 47

def parts
  @parts
end

#sObject (readonly) Also known as: to_s

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



47
48
49
# File 'lib/smart_name.rb', line 47

def s
  @s
end

#simpleObject (readonly) Also known as: simple?

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



47
48
49
# File 'lib/smart_name.rb', line 47

def simple
  @simple
end

Class Method Details

.banned_reObject



38
39
40
# File 'lib/smart_name.rb', line 38

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

.new(obj) ⇒ Object



28
29
30
31
32
33
34
35
36
# File 'lib/smart_name.rb', line 28

def new obj
  return obj if self.class===obj
  str = Array===obj ? 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???



246
247
248
249
250
251
252
253
# File 'lib/smart_name.rb', line 246

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

#==(obj) ⇒ Object



82
83
84
85
86
87
88
89
# File 'lib/smart_name.rb', line 82

def == obj
  object_key = case
    when obj.respond_to?(:key)     ; obj.key
    when obj.respond_to?(:to_name) ; obj.to_name.key
    else                           ; obj.to_s
    end
  object_key == key
end

#blank?Boolean Also known as: empty?

Returns:

  • (Boolean)


69
# File 'lib/smart_name.rb', line 69

def blank?()     s.blank?     end

#decodedObject



106
107
108
# File 'lib/smart_name.rb', line 106

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

#inspectObject



78
79
80
# File 'lib/smart_name.rb', line 78

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

#junction?Boolean

Returns:

  • (Boolean)


124
# File 'lib/smart_name.rb', line 124

def junction?()   not simple?                                             end

#leftObject



126
# File 'lib/smart_name.rb', line 126

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

#left_nameObject



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

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

#lengthObject



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

def length()     parts.length end

#nth_left(n) ⇒ Object



210
211
212
213
# File 'lib/smart_name.rb', line 210

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



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

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

#piece_namesObject



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

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

#piecesObject



143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/smart_name.rb', line 143

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

#post_cgiObject



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

def post_cgi
  #hmm.  this could resolve to the key of some other card.  move to class method?
  @post_cgi ||= s.gsub '~plus~', self.class.joint
end

#pre_cgiObject



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

def pre_cgi
  #why is this necessary?? doesn't real CGI escaping handle this??
  # hmmm.  is this to prevent absolutizing
  @pre_cgi ||= parts.join '~plus~'
end

#replace_part(oldpart, newpart) ⇒ Object

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



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/smart_name.rb', line 218

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 self.length == oldpart.length
        newpart
      else
        (newpart.parts+(parts[oldpart.length,].lines.to_a)).to_name
      end
    else
      self
    end
  end
end

#rightObject



127
# File 'lib/smart_name.rb', line 127

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

#right_nameObject



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

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

#safe_keyObject



102
103
104
# File 'lib/smart_name.rb', line 102

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

#simple_keyObject

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



94
95
96
# File 'lib/smart_name.rb', line 94

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

#sizeObject



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

def size()       to_s.size    end

#tagObject



135
# File 'lib/smart_name.rb', line 135

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

#tag_nameObject



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

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

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



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/smart_name.rb', line 179

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 and name_proc.call or part
      when /^_main$/i;            self.class.params[:main_name]
      when /^(_self|_whole|_)$/i; context.s
      when /^_left$/i;            context.trunk #note - inconsistent use of left v. trunk
      when /^_right$/i;           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



206
207
208
# File 'lib/smart_name.rb', line 206

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

#to_nameObject



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

def to_name()    self         end

#to_show(*ignore) ⇒ Object

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



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/smart_name.rb', line 161

def to_show *ignore
  ignore.map! &:to_name

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

  show_name = show_parts.compact.to_name.s
  
  case
  when show_parts.compact.empty?;  self
  when show_parts[0].nil?       ;  self.class.joint + show_name
  else show_name
  end
end

#trunkObject

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



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

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

#trunk_nameObject



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

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

#url_keyObject



98
99
100
# File 'lib/smart_name.rb', line 98

def url_key
  @url_key ||= decoded.gsub(/[^#{OK4KEY_RE}#{JOINT_RE}]+/,' ').strip.gsub /[\s\_]+/, '_'
end

#valid?Boolean

Returns:

  • (Boolean)


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

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