smartname 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +14 -0
- data/Gemfile.lock +39 -0
- data/README.rdoc +7 -0
- data/Rakefile +66 -0
- data/VERSION +1 -0
- data/lib/smart_name.rb +274 -0
- data/spec/inflection_helper.rb +12 -0
- data/spec/lib/smart_name_spec.rb +251 -0
- data/spec/spec_helper.rb +26 -0
- metadata +159 -0
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Add dependencies to develop your gem here.
|
4
|
+
# Include everything needed to run rake, tests, features, etc.
|
5
|
+
group :development do
|
6
|
+
gem "rspec", "~> 2.8.0"
|
7
|
+
gem "rdoc", "~> 3.12"
|
8
|
+
gem "bundler", "~> 1.1.0"
|
9
|
+
gem "jeweler", "~> 1.8.3"
|
10
|
+
#gem "rcov", ">= 0"
|
11
|
+
end
|
12
|
+
|
13
|
+
gem "activesupport"
|
14
|
+
gem 'htmlentities', '~>4.3.0'
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.2.8)
|
5
|
+
i18n (~> 0.6)
|
6
|
+
multi_json (~> 1.0)
|
7
|
+
diff-lcs (1.1.3)
|
8
|
+
git (1.2.5)
|
9
|
+
htmlentities (4.3.1)
|
10
|
+
i18n (0.6.1)
|
11
|
+
jeweler (1.8.3)
|
12
|
+
bundler (~> 1.0)
|
13
|
+
git (>= 1.2.5)
|
14
|
+
rake
|
15
|
+
rdoc
|
16
|
+
json (1.7.5)
|
17
|
+
multi_json (1.3.6)
|
18
|
+
rake (0.9.2.2)
|
19
|
+
rdoc (3.12)
|
20
|
+
json (~> 1.4)
|
21
|
+
rspec (2.8.0)
|
22
|
+
rspec-core (~> 2.8.0)
|
23
|
+
rspec-expectations (~> 2.8.0)
|
24
|
+
rspec-mocks (~> 2.8.0)
|
25
|
+
rspec-core (2.8.0)
|
26
|
+
rspec-expectations (2.8.0)
|
27
|
+
diff-lcs (~> 1.1.2)
|
28
|
+
rspec-mocks (2.8.0)
|
29
|
+
|
30
|
+
PLATFORMS
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
activesupport
|
35
|
+
bundler (~> 1.1.0)
|
36
|
+
htmlentities (~> 4.3.0)
|
37
|
+
jeweler (~> 1.8.3)
|
38
|
+
rdoc (~> 3.12)
|
39
|
+
rspec (~> 2.8.0)
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
|
7
|
+
VERSION = File.exist?('VERSION') ? File.read('VERSION') : ""
|
8
|
+
|
9
|
+
begin
|
10
|
+
Bundler.setup(:default, :development)
|
11
|
+
rescue Bundler::BundlerError => e
|
12
|
+
$stderr.puts e.message
|
13
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
14
|
+
exit e.status_code
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'rake'
|
18
|
+
|
19
|
+
begin
|
20
|
+
require 'jeweler'
|
21
|
+
Jeweler::Tasks.new do |gem|
|
22
|
+
gem.name = 'smartname'
|
23
|
+
gem.version = VERSION
|
24
|
+
gem.license = "GPL-2"
|
25
|
+
gem.summary = "Wagn names without all the wagn"
|
26
|
+
gem.email = "gerryg@inbox.com"
|
27
|
+
gem.homepage = "https://github.com/wagn/smartname"
|
28
|
+
gem.description = "Wagn names without all the wagn"
|
29
|
+
gem.authors = ["Gerry Gleason <gerryg@inbox.com>", "Ethan McCutchen <ethan@wagn.org>"]
|
30
|
+
gem.files = FileList[
|
31
|
+
'[A-Z]*',
|
32
|
+
'*.rb',
|
33
|
+
'lib/**/*.rb',
|
34
|
+
'spec/**/*.rb' ].to_a
|
35
|
+
gem.test_files = Dir.glob('spec/*_spec.rb')
|
36
|
+
gem.has_rdoc = true
|
37
|
+
gem.extra_rdoc_files = [ "README.rdoc", "CHANGES" ]
|
38
|
+
gem.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"]
|
39
|
+
end
|
40
|
+
rescue LoadError
|
41
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
42
|
+
end
|
43
|
+
|
44
|
+
Jeweler::RubygemsDotOrgTasks.new
|
45
|
+
|
46
|
+
require 'rspec/core'
|
47
|
+
require 'rspec/core/rake_task'
|
48
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
49
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
50
|
+
end
|
51
|
+
|
52
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
53
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
54
|
+
spec.rcov = true
|
55
|
+
end
|
56
|
+
|
57
|
+
task :default => :spec
|
58
|
+
|
59
|
+
require 'rdoc/task'
|
60
|
+
Rake::RDocTask.new do |rdoc|
|
61
|
+
|
62
|
+
rdoc.rdoc_dir = 'rdoc'
|
63
|
+
rdoc.title = "smartname #{VERSION}"
|
64
|
+
rdoc.rdoc_files.include('README*')
|
65
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
66
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/smart_name.rb
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'active_support/configurable'
|
4
|
+
require 'active_support/inflector'
|
5
|
+
|
6
|
+
class Object
|
7
|
+
def to_name() SmartName.new(self) end
|
8
|
+
end
|
9
|
+
|
10
|
+
class SmartName < Object
|
11
|
+
require 'htmlentities'
|
12
|
+
RUBY19 = RUBY_VERSION =~ /^1\.9/
|
13
|
+
WORD_RE = RUBY19 ? '\p{Word}' : '\w'
|
14
|
+
|
15
|
+
include ActiveSupport::Configurable
|
16
|
+
|
17
|
+
config_accessor :joint, :formal_joint, :name_attribute, :banned_array,
|
18
|
+
:var_re, :uninflect, :params, :codes, :lookup
|
19
|
+
|
20
|
+
# Wagny defaults:
|
21
|
+
JOINT = '+'
|
22
|
+
SmartName.joint = JOINT
|
23
|
+
SmartName.formal_joint = " <span class=\"wiki-joint\">#{JOINT}</span> "
|
24
|
+
SmartName.banned_array = [ '/', '~', '|' ]
|
25
|
+
SmartName.name_attribute = :cardname
|
26
|
+
SmartName.var_re = /\{([^\}]*})\}/
|
27
|
+
SmartName.uninflect = :singularize
|
28
|
+
|
29
|
+
@@name2nameobject = {}
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def new obj
|
33
|
+
return obj if SmartName===obj
|
34
|
+
str = Array===obj ? obj*SmartName.joint : obj.to_s
|
35
|
+
if known_name = @@name2nameobject[str]
|
36
|
+
known_name
|
37
|
+
else
|
38
|
+
super str.strip
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def unescape uri
|
43
|
+
# can't instantiate because key doesn't resolve correctly in unescaped form
|
44
|
+
# issue is peculiar to plus sign (+), which are interpreted as a space.
|
45
|
+
# if we could make that not happen, we could avoid this (and handle spaces in urls)
|
46
|
+
uri.gsub(' ','+').gsub '_',' '
|
47
|
+
end
|
48
|
+
|
49
|
+
def banned_re
|
50
|
+
%r{#{ (['['] + SmartName.banned_array << SmartName.joint )*'\\' + ']' }}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
56
|
+
#~~~~~~~~~~~~~~~~~~~~~~ INSTANCE ~~~~~~~~~~~~~~~~~~~~~~~~~
|
57
|
+
|
58
|
+
attr_reader :simple, :parts, :key, :s
|
59
|
+
alias to_s s
|
60
|
+
|
61
|
+
def initialize str
|
62
|
+
@s = str.to_s.strip
|
63
|
+
@s = @s.encode('UTF-8') if RUBY19
|
64
|
+
@key = if @s.index(SmartName.joint)
|
65
|
+
@parts = @s.split(/\s*#{Regexp.escape(SmartName.joint)}\s*/)
|
66
|
+
@parts << '' if @s[-1] == SmartName.joint
|
67
|
+
@simple = false
|
68
|
+
@parts.map { |p| p.to_name.key } * SmartName.joint
|
69
|
+
else
|
70
|
+
@parts = [str]
|
71
|
+
@simple = true
|
72
|
+
str.empty? ? '' : simple_key
|
73
|
+
end
|
74
|
+
@@name2nameobject[str] = self
|
75
|
+
end
|
76
|
+
|
77
|
+
def valid?()
|
78
|
+
not parts.find { |pt| pt.match SmartName.banned_re }
|
79
|
+
end
|
80
|
+
def to_name() self end
|
81
|
+
def length() parts.length end
|
82
|
+
def size() to_s.size end
|
83
|
+
def blank?() s.blank? end
|
84
|
+
alias empty? blank?
|
85
|
+
|
86
|
+
def inspect
|
87
|
+
"<SmartName key=#{key}[#{self}]>"
|
88
|
+
end
|
89
|
+
|
90
|
+
def == obj
|
91
|
+
object_key = case
|
92
|
+
when obj.respond_to?(:key) ; obj.key
|
93
|
+
when obj.respond_to?(:to_name) ; obj.to_name.key
|
94
|
+
else ; obj.to_s
|
95
|
+
end
|
96
|
+
object_key == key
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
#~~~~~~~~~~~~~~~~~~~ VARIANTS ~~~~~~~~~~~~~~~~~~~
|
101
|
+
|
102
|
+
def simple_key
|
103
|
+
decoded.underscore.gsub(/[^#{WORD_RE}\*]+/,'_').split(/_+/).reject(&:empty?).map(&(SmartName.uninflect))*'_'
|
104
|
+
end
|
105
|
+
|
106
|
+
def url_key
|
107
|
+
@url_key ||= decoded.gsub(/[^\*#{WORD_RE}\s\+]/,' ').strip.gsub(/[\s\_]+/,'_')
|
108
|
+
end
|
109
|
+
|
110
|
+
def safe_key
|
111
|
+
@safe_key ||= key.gsub('*','X').gsub SmartName.joint, '-'
|
112
|
+
end
|
113
|
+
|
114
|
+
def decoded
|
115
|
+
@decoded ||= (s.index('&') ? HTMLEntities.new.decode(s) : s)
|
116
|
+
end
|
117
|
+
|
118
|
+
def pre_cgi
|
119
|
+
#why is this necessary?? doesn't real CGI escaping handle this??
|
120
|
+
# hmmm. is this to prevent absolutizing
|
121
|
+
@pre_cgi ||= parts.join '~plus~'
|
122
|
+
end
|
123
|
+
|
124
|
+
def post_cgi
|
125
|
+
#hmm. this could resolve to the key of some other card. move to class method?
|
126
|
+
@post_cgi ||= s.gsub '~plus~', SmartName.joint
|
127
|
+
end
|
128
|
+
|
129
|
+
#~~~~~~~~~~~~~~~~~~~ PARTS ~~~~~~~~~~~~~~~~~~~
|
130
|
+
|
131
|
+
alias simple? simple
|
132
|
+
def junction?() not simple? end
|
133
|
+
|
134
|
+
def left() @left ||= simple? ? nil : parts[0..-2]*SmartName.joint end
|
135
|
+
def right() @right ||= simple? ? nil : parts[-1] end
|
136
|
+
|
137
|
+
def left_name() @left_name ||= left && SmartName.new( left ) end
|
138
|
+
def right_name() @right_name ||= right && SmartName.new( right ) end
|
139
|
+
|
140
|
+
# Note that all names have a trunk and tag, but only junctions have left and right
|
141
|
+
|
142
|
+
def trunk() @trunk ||= simple? ? s : left end
|
143
|
+
def tag() @tag ||= simple? ? s : right end
|
144
|
+
|
145
|
+
def trunk_name() @trunk_name ||= simple? ? self : left_name end
|
146
|
+
def tag_name() @tag_name ||= simple? ? self : right_name end
|
147
|
+
|
148
|
+
def pieces
|
149
|
+
@pieces ||= if simple?
|
150
|
+
[ self ]
|
151
|
+
else
|
152
|
+
trunk_name.pieces + [ tag_name ]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
#~~~~~~~~~~~~~~~~~~~ TRAITS / STARS ~~~~~~~~~~~~~~~~~~~
|
158
|
+
|
159
|
+
def star?() simple? and '*' == s[0] end
|
160
|
+
def rstar?() right and '*' == right[0] end
|
161
|
+
|
162
|
+
def trait_name? *traitlist
|
163
|
+
junction? && begin
|
164
|
+
right_key = right_name.key
|
165
|
+
!!traitlist.find do |codename|
|
166
|
+
codecard = SmartName.codes[ codename ] and codecard = SmartName.lookup[ codecard ] and
|
167
|
+
codecard.send(SmartName.name_attribute).key == right_key
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def trait_name tag_code
|
173
|
+
codecard = SmartName.codes[ tag_code ] and codecard = SmartName.lookup[ codecard ] and
|
174
|
+
[ self, codecard.send(SmartName.name_attribute) ].to_name
|
175
|
+
end
|
176
|
+
|
177
|
+
def trait tag_code
|
178
|
+
trait_name( tag_code ).s
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
#~~~~~~~~~~~~~~~~~~~~ SHOW / ABSOLUTE ~~~~~~~~~~~~~~~~~~~~
|
184
|
+
|
185
|
+
def to_show context, args={}
|
186
|
+
# ignore = [ args[:ignore], context.to_name.parts ].flatten.compact.map &:to_name
|
187
|
+
ignore = [ args[:ignore] ].flatten.map &:to_name
|
188
|
+
fullname = parts.to_name.to_absolute_name context, args
|
189
|
+
|
190
|
+
show_parts = fullname.parts.map do |part|
|
191
|
+
reject = ( part.empty? or part =~ /^_/ or ignore.member? part.to_name )
|
192
|
+
reject ? nil : part
|
193
|
+
end
|
194
|
+
|
195
|
+
initial_blank = show_parts[0].nil?
|
196
|
+
show_name = show_parts.compact.to_name.s
|
197
|
+
|
198
|
+
initial_blank ? SmartName.joint + show_name : show_name
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
def to_absolute context, args={}
|
203
|
+
context = context.to_name
|
204
|
+
parts.map do |part|
|
205
|
+
new_part = case part
|
206
|
+
when /^_user$/i; (user=Session.user_card) ? user.name : part
|
207
|
+
when /^_main$/i; SmartName.params[:main_name]
|
208
|
+
when /^(_self|_whole|_)$/i; context.s
|
209
|
+
when /^_left$/i; context.trunk #note - inconsistent use of left v. trunk
|
210
|
+
when /^_right$/i; context.tag
|
211
|
+
when /^_(\d+)$/i
|
212
|
+
pos = $~[1].to_i
|
213
|
+
pos = context.length if pos > context.length
|
214
|
+
context.parts[pos-1]
|
215
|
+
when /^_(L*)(R?)$/i
|
216
|
+
l_s, r_s = $~[1].size, !$~[2].empty?
|
217
|
+
l_part = context.nth_left l_s
|
218
|
+
r_s ? l_part.tag : l_part.s
|
219
|
+
when /^_/
|
220
|
+
custom = args[:params] ? args[:params][part] : nil
|
221
|
+
custom ? CGI.escapeHTML(custom) : part #why are we escaping HTML here?
|
222
|
+
else
|
223
|
+
part
|
224
|
+
end.to_s.strip
|
225
|
+
new_part.empty? ? context.to_s : new_part
|
226
|
+
end * SmartName.joint
|
227
|
+
end
|
228
|
+
|
229
|
+
def to_absolute_name *args
|
230
|
+
SmartName.new to_absolute(*args)
|
231
|
+
end
|
232
|
+
|
233
|
+
def nth_left n
|
234
|
+
# 1 = left; 2= left of left; 3 = left of left of left....
|
235
|
+
( n >= length ? parts[0] : parts[0..-n-1] ).to_name
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
#~~~~~~~~~~~~~~~~~~~~ MISC ~~~~~~~~~~~~~~~~~~~~
|
240
|
+
|
241
|
+
def replace_part oldpart, newpart
|
242
|
+
oldpart = oldpart.to_name
|
243
|
+
newpart = newpart.to_name
|
244
|
+
if oldpart.simple?
|
245
|
+
if simple?
|
246
|
+
self == oldpart ? newpart : self
|
247
|
+
else
|
248
|
+
parts.map do |p|
|
249
|
+
oldpart == p ? newpart.to_s : p
|
250
|
+
end.to_name
|
251
|
+
end
|
252
|
+
elsif simple?
|
253
|
+
self
|
254
|
+
else
|
255
|
+
if oldpart == parts[0, oldpart.length]
|
256
|
+
if self.length == oldpart.length
|
257
|
+
newpart
|
258
|
+
else
|
259
|
+
(newpart.parts+(parts[oldpart.length,].lines.to_a)).to_name
|
260
|
+
end
|
261
|
+
else
|
262
|
+
self
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def self.substitute! str, hash
|
268
|
+
hash.keys.each do |var|
|
269
|
+
str.gsub!(SmartName.var_re) { |x| (v=hash[var.to_sym]).nil? ? x : v }
|
270
|
+
end
|
271
|
+
str
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Add new inflection rules using the following format
|
4
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
5
|
+
inflect.irregular 'grave', 'graveyard'
|
6
|
+
inflect.uncountable 'this'
|
7
|
+
# inflect.uncountable 'plus'
|
8
|
+
inflect.uncountable 'anonymous'
|
9
|
+
inflect.uncountable /^s$/
|
10
|
+
inflect.singular(/(ss)$/i, '\1')
|
11
|
+
inflect.plural(/(ss)$/i, '\1')
|
12
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
describe SmartName do
|
5
|
+
|
6
|
+
describe "#key" do
|
7
|
+
it "should remove spaces" do
|
8
|
+
"this Name".to_name.key.should == "this_name"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have initial _ for initial cap" do
|
12
|
+
"This Name".to_name.key.should == "this_name"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have initial _ for initial cap" do
|
16
|
+
"_This Name".to_name.key.should == "this_name"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should singularize" do
|
20
|
+
"ethans".to_name.key.should == "ethan"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should underscore" do
|
24
|
+
"ThisThing".to_name.key.should == "this_thing"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should handle plus cards" do
|
28
|
+
"ThisThing+Ethans".to_name.key.should == "this_thing+ethan"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should retain * for star cards" do
|
32
|
+
"*right".to_name.key.should == "*right"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not singularize double s's" do
|
36
|
+
"grass".to_name.key.should == 'grass'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not singularize letter 'S'" do
|
40
|
+
'S'.to_name.key.should == 's'
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should handle unicode characters" do
|
44
|
+
"Mañana".to_name.key.should == 'mañana'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should handle weird initial characters" do
|
48
|
+
'__you motha @#$'.to_name.key.should == 'you_motha'
|
49
|
+
'?!_you motha @#$'.to_name.key.should == 'you_motha'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should allow numbers" do
|
53
|
+
"3way".to_name.key.should == '3way'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "internal plurals" do
|
57
|
+
"cards hooks label foos".to_name.key.should == 'card_hook_label_foo'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should handle html entities" do
|
61
|
+
# This no longer takes off the s, is singularize broken now?
|
62
|
+
"Jean-françois Noubel".to_name.key.should == 'jean_françoi_noubel'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
describe "#url_key" do
|
71
|
+
cardnames = ["GrassCommons.org", 'Oh you @##', "Alice's Restaurant!", "PB & J", "Mañana"].map(&:to_name)
|
72
|
+
|
73
|
+
cardnames.each do |cardname|
|
74
|
+
it "should have the same key as the name" do
|
75
|
+
k, k2 = cardname.key, cardname.url_key
|
76
|
+
#warn "cn tok #{cardname.inspect}, #{k.inspect}, #{k2.inspect}"
|
77
|
+
k.should == k2.to_name.key
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#valid" do
|
83
|
+
it "accepts valid names" do
|
84
|
+
"this+THAT".to_name.should be_valid
|
85
|
+
"THE*ONE*AND$!ONLY".to_name.should be_valid
|
86
|
+
end
|
87
|
+
|
88
|
+
it "rejects invalide names" do
|
89
|
+
"Tes~sd".to_name.should_not be_valid
|
90
|
+
"TEST/DDER".to_name.should_not be_valid
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#left_name" do
|
95
|
+
it "returns nil for non junction" do
|
96
|
+
"a".to_name.left_name.should == nil
|
97
|
+
end
|
98
|
+
|
99
|
+
it "returns parent for parent" do
|
100
|
+
"a+b+c+d".to_name.left_name.should == "a+b+c"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "#tag_name" do
|
105
|
+
it "returns last part of plus card" do
|
106
|
+
"a+b+c".to_name.tag.should == "c"
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns name of simple card" do
|
110
|
+
"a".to_name.tag.should == "a"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#safe_key" do
|
115
|
+
it "subs pluses & stars" do
|
116
|
+
"Alpha?+*be-ta".to_name.safe_key.should == "alpha-Xbe_tum"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "#replace_part" do
|
121
|
+
it "replaces first name part" do
|
122
|
+
'a+b'.to_name.replace_part('a','x').to_s.should == 'x+b'
|
123
|
+
end
|
124
|
+
it "replaces second name part" do
|
125
|
+
'a+b'.to_name.replace_part('b','x').to_s.should == 'a+x'
|
126
|
+
end
|
127
|
+
it "replaces two name parts" do
|
128
|
+
'a+b+c'.to_name.replace_part('a+b','x').to_s.should == 'x+c'
|
129
|
+
end
|
130
|
+
it "doesn't replace two part tag" do
|
131
|
+
'a+b+c'.to_name.replace_part('b+c','x').to_s.should == 'a+b+c'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "Cardnames star handling" do
|
136
|
+
it "recognizes star cards" do
|
137
|
+
'*a'.to_name.star?.should be_true
|
138
|
+
end
|
139
|
+
|
140
|
+
it "doesn't recognize star cards with plusses" do
|
141
|
+
'*a+*b'.to_name.star?.should be_false
|
142
|
+
end
|
143
|
+
|
144
|
+
it "recognizes rstar cards" do
|
145
|
+
'a+*a'.to_name.rstar?.should be_true
|
146
|
+
end
|
147
|
+
|
148
|
+
it "doesn't recognize star cards as rstar" do
|
149
|
+
'*a'.to_name.rstar?.should be_false
|
150
|
+
end
|
151
|
+
|
152
|
+
it "doesn't recognize non-star or star left" do
|
153
|
+
'*a+a'.to_name.rstar?.should be_false
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "trait_name?" do
|
158
|
+
it "returns true for content codename" do
|
159
|
+
"bazoinga+*right+*content".to_name.trait_name?(:content).should be_true
|
160
|
+
end
|
161
|
+
|
162
|
+
it "handles arrays" do
|
163
|
+
"bazoinga+*right+*content".to_name.trait_name?(:content, :default).should be_true
|
164
|
+
end
|
165
|
+
|
166
|
+
it "returns false for non-template" do
|
167
|
+
"bazoinga+*right+nontent".to_name.trait_name?(:content).should be_false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "#to_absolute" do
|
172
|
+
it "handles _self, _whole, _" do
|
173
|
+
"_self".to_name.to_absolute("foo").should == "foo"
|
174
|
+
"_whole".to_name.to_absolute("foo").should == "foo"
|
175
|
+
"_".to_name.to_absolute("foo").should == "foo"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "handles _left" do
|
179
|
+
"_left+Z".to_name.to_absolute("A+B+C").should == "A+B+Z"
|
180
|
+
end
|
181
|
+
|
182
|
+
it "handles white space" do
|
183
|
+
"_left + Z".to_name.to_absolute("A+B+C").should == "A+B+Z"
|
184
|
+
end
|
185
|
+
|
186
|
+
it "handles _right" do
|
187
|
+
"_right+bang".to_name.to_absolute("nutter+butter").should == "butter+bang"
|
188
|
+
"C+_right".to_name.to_absolute("B+A").should == "C+A"
|
189
|
+
end
|
190
|
+
|
191
|
+
it "handles leading +" do
|
192
|
+
"+bug".to_name.to_absolute("hum").should == "hum+bug"
|
193
|
+
end
|
194
|
+
|
195
|
+
it "handles trailing +" do
|
196
|
+
"bug+".to_name.to_absolute("tracks").should == "bug+tracks"
|
197
|
+
end
|
198
|
+
|
199
|
+
it "handles _(numbers)" do
|
200
|
+
"_1".to_name.to_absolute("A+B+C").should == "A"
|
201
|
+
"_1+_2".to_name.to_absolute("A+B+C").should == "A+B"
|
202
|
+
"_2+_3".to_name.to_absolute("A+B+C").should == "B+C"
|
203
|
+
end
|
204
|
+
|
205
|
+
it "handles _LLR etc" do
|
206
|
+
"_R".to_name.to_absolute("A+B+C+D+E").should == "E"
|
207
|
+
"_L".to_name.to_absolute("A+B+C+D+E").should == "A+B+C+D"
|
208
|
+
"_LR".to_name.to_absolute("A+B+C+D+E").should == "D"
|
209
|
+
"_LL".to_name.to_absolute("A+B+C+D+E").should == "A+B+C"
|
210
|
+
"_LLR".to_name.to_absolute("A+B+C+D+E").should == "C"
|
211
|
+
"_LLL".to_name.to_absolute("A+B+C+D+E").should == "A+B"
|
212
|
+
"_LLLR".to_name.to_absolute("A+B+C+D+E").should == "B"
|
213
|
+
"_LLLL".to_name.to_absolute("A+B+C+D+E").should == "A"
|
214
|
+
end
|
215
|
+
|
216
|
+
context "mismatched requests" do
|
217
|
+
it "returns _self for _left or _right on simple cards" do
|
218
|
+
"_left+Z".to_name.to_absolute("A").should == "A+Z"
|
219
|
+
"_right+Z".to_name.to_absolute("A").should == "A+Z"
|
220
|
+
end
|
221
|
+
|
222
|
+
it "handles bogus numbers" do
|
223
|
+
"_1".to_name.to_absolute("A").should == "A"
|
224
|
+
"_1+_2".to_name.to_absolute("A").should == "A+A"
|
225
|
+
"_2+_3".to_name.to_absolute("A").should == "A+A"
|
226
|
+
end
|
227
|
+
|
228
|
+
it "handles bogus _llr requests" do
|
229
|
+
"_R".to_name.to_absolute("A").should == "A"
|
230
|
+
"_L".to_name.to_absolute("A").should == "A"
|
231
|
+
"_LR".to_name.to_absolute("A").should == "A"
|
232
|
+
"_LL".to_name.to_absolute("A").should == "A"
|
233
|
+
"_LLR".to_name.to_absolute("A").should == "A"
|
234
|
+
"_LLL".to_name.to_absolute("A").should == "A"
|
235
|
+
"_LLLR".to_name.to_absolute("A").should == "A"
|
236
|
+
"_LLLL".to_name.to_absolute("A").should == "A"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe "#to_show" do
|
242
|
+
it "ignores ignorables" do
|
243
|
+
'you+awe'.to_name.to_show('A', :ignore=>'you' ).should == '+awe'
|
244
|
+
'me+you+awe'.to_name.to_show('A', :ignore=>'you' ).should == 'me+awe' #HMMM..... what should this do?
|
245
|
+
'me+you+awe'.to_name.to_show('A', :ignore=>['me','you'] ).should == '+awe'
|
246
|
+
'_left+_right+awe'.to_name.to_show('A+B', :ignore=>'A' ).should == '+B+awe'
|
247
|
+
'?a?+awe'.to_name.to_show('B', :ignore=>'A' ).should == '+awe'
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
require 'smart_name'
|
3
|
+
require File.expand_path('./inflection_helper', File.dirname(__FILE__))
|
4
|
+
|
5
|
+
class CardMock < String
|
6
|
+
def name() to_name end
|
7
|
+
end
|
8
|
+
|
9
|
+
SmartName.name_attribute= :name
|
10
|
+
SmartName.codes= { :content => 1 }
|
11
|
+
SmartName.lookup= { 1 => CardMock.new('*content'), }
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
|
15
|
+
#config.include CustomMatchers
|
16
|
+
#config.include ControllerMacros, :type=>:controllers
|
17
|
+
#config.include AuthenticatedTestHelper, :type=>:controllers
|
18
|
+
#config.include(EmailSpec::Helpers)
|
19
|
+
#config.include(EmailSpec::Matchers)
|
20
|
+
|
21
|
+
# == Mock Framework
|
22
|
+
# If you prefer to mock with mocha, flexmock or RR, uncomment the appropriate symbol:
|
23
|
+
# :mocha, :flexmock, :rr
|
24
|
+
|
25
|
+
end
|
26
|
+
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smartname
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gerry Gleason <gerryg@inbox.com>
|
9
|
+
- Ethan McCutchen <ethan@wagn.org>
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-11-20 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: htmlentities
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 4.3.0
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 4.3.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.8.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.8.0
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rdoc
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '3.12'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '3.12'
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: bundler
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ~>
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 1.1.0
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ~>
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 1.1.0
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: jeweler
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ~>
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 1.8.3
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.8.3
|
111
|
+
description: Wagn names without all the wagn
|
112
|
+
email: gerryg@inbox.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files:
|
116
|
+
- README.rdoc
|
117
|
+
files:
|
118
|
+
- Gemfile
|
119
|
+
- Gemfile.lock
|
120
|
+
- README.rdoc
|
121
|
+
- Rakefile
|
122
|
+
- VERSION
|
123
|
+
- lib/smart_name.rb
|
124
|
+
- spec/inflection_helper.rb
|
125
|
+
- spec/lib/smart_name_spec.rb
|
126
|
+
- spec/spec_helper.rb
|
127
|
+
homepage: https://github.com/wagn/smartname
|
128
|
+
licenses:
|
129
|
+
- GPL-2
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options:
|
132
|
+
- --main
|
133
|
+
- README.rdoc
|
134
|
+
- --inline-source
|
135
|
+
- --line-numbers
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
segments:
|
145
|
+
- 0
|
146
|
+
hash: 239023093442111674
|
147
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 1.8.24
|
156
|
+
signing_key:
|
157
|
+
specification_version: 3
|
158
|
+
summary: Wagn names without all the wagn
|
159
|
+
test_files: []
|