cardname 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +91 -0
- data/README.rdoc +7 -0
- data/Rakefile +39 -0
- data/lib/cardname/contextual.rb +114 -0
- data/lib/cardname/manipulate.rb +73 -0
- data/lib/cardname/parts.rb +126 -0
- data/lib/cardname/predicates.rb +39 -0
- data/lib/cardname/variants.rb +36 -0
- data/lib/cardname.rb +114 -0
- data/lib/core_ext.rb +5 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 15f37bd2c96222cfff562f06782c52e27a803dc0
|
4
|
+
data.tar.gz: 86752b10ed33282d3cafa93eaca1320aea1e8e94
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d66817487594c22c30d7f1374c53711312c6d314609ec0d34ac8724def65bb7e853f1a5ce5e29a03aec902b4c28d136d535b2cbae2e87d7fa069575139ed8fdf
|
7
|
+
data.tar.gz: a3867d0234a9f27360e3bcf47328c5ff1380066b1af3ffad1487578796c0f6a47f14b5008d970d87b3ae3697fb12c86ebeafc8753d19cf13f9178437b416e498
|
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"
|
7
|
+
gem "rdoc"
|
8
|
+
gem "bundler"
|
9
|
+
gem "jeweler"
|
10
|
+
#gem "rcov"
|
11
|
+
end
|
12
|
+
|
13
|
+
gem "activesupport"
|
14
|
+
gem 'htmlentities'
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (5.0.1)
|
5
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
6
|
+
i18n (~> 0.7)
|
7
|
+
minitest (~> 5.1)
|
8
|
+
tzinfo (~> 1.1)
|
9
|
+
addressable (2.5.0)
|
10
|
+
public_suffix (~> 2.0, >= 2.0.2)
|
11
|
+
builder (3.2.3)
|
12
|
+
concurrent-ruby (1.0.4)
|
13
|
+
descendants_tracker (0.0.4)
|
14
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
15
|
+
diff-lcs (1.3)
|
16
|
+
faraday (0.9.2)
|
17
|
+
multipart-post (>= 1.2, < 3)
|
18
|
+
git (1.3.0)
|
19
|
+
github_api (0.11.3)
|
20
|
+
addressable (~> 2.3)
|
21
|
+
descendants_tracker (~> 0.0.1)
|
22
|
+
faraday (~> 0.8, < 0.10)
|
23
|
+
hashie (>= 1.2)
|
24
|
+
multi_json (>= 1.7.5, < 2.0)
|
25
|
+
nokogiri (~> 1.6.0)
|
26
|
+
oauth2
|
27
|
+
hashie (3.5.4)
|
28
|
+
highline (1.7.8)
|
29
|
+
htmlentities (4.3.4)
|
30
|
+
i18n (0.8.1)
|
31
|
+
jeweler (2.3.3)
|
32
|
+
builder
|
33
|
+
bundler (>= 1.0)
|
34
|
+
git (>= 1.2.5)
|
35
|
+
github_api (~> 0.11.0)
|
36
|
+
highline (>= 1.6.15)
|
37
|
+
nokogiri (>= 1.5.10)
|
38
|
+
psych (~> 2.2)
|
39
|
+
rake
|
40
|
+
rdoc
|
41
|
+
semver2
|
42
|
+
jwt (1.5.6)
|
43
|
+
mini_portile2 (2.1.0)
|
44
|
+
minitest (5.10.1)
|
45
|
+
multi_json (1.12.1)
|
46
|
+
multi_xml (0.6.0)
|
47
|
+
multipart-post (2.0.0)
|
48
|
+
nokogiri (1.6.8.1)
|
49
|
+
mini_portile2 (~> 2.1.0)
|
50
|
+
oauth2 (1.3.0)
|
51
|
+
faraday (>= 0.8, < 0.11)
|
52
|
+
jwt (~> 1.0)
|
53
|
+
multi_json (~> 1.3)
|
54
|
+
multi_xml (~> 0.5)
|
55
|
+
rack (>= 1.2, < 3)
|
56
|
+
psych (2.2.4)
|
57
|
+
public_suffix (2.0.5)
|
58
|
+
rack (2.0.1)
|
59
|
+
rake (12.0.0)
|
60
|
+
rdoc (5.1.0)
|
61
|
+
rspec (3.5.0)
|
62
|
+
rspec-core (~> 3.5.0)
|
63
|
+
rspec-expectations (~> 3.5.0)
|
64
|
+
rspec-mocks (~> 3.5.0)
|
65
|
+
rspec-core (3.5.4)
|
66
|
+
rspec-support (~> 3.5.0)
|
67
|
+
rspec-expectations (3.5.0)
|
68
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
69
|
+
rspec-support (~> 3.5.0)
|
70
|
+
rspec-mocks (3.5.0)
|
71
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
72
|
+
rspec-support (~> 3.5.0)
|
73
|
+
rspec-support (3.5.0)
|
74
|
+
semver2 (3.4.2)
|
75
|
+
thread_safe (0.3.6)
|
76
|
+
tzinfo (1.2.2)
|
77
|
+
thread_safe (~> 0.1)
|
78
|
+
|
79
|
+
PLATFORMS
|
80
|
+
ruby
|
81
|
+
|
82
|
+
DEPENDENCIES
|
83
|
+
activesupport
|
84
|
+
bundler
|
85
|
+
htmlentities
|
86
|
+
jeweler
|
87
|
+
rdoc
|
88
|
+
rspec
|
89
|
+
|
90
|
+
BUNDLED WITH
|
91
|
+
1.12.5
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
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
|
+
require 'rspec/core'
|
20
|
+
require 'rspec/core/rake_task'
|
21
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
22
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
26
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
27
|
+
spec.rcov = true
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => :spec
|
31
|
+
|
32
|
+
require 'rdoc/task'
|
33
|
+
Rake::RDocTask.new do |rdoc|
|
34
|
+
|
35
|
+
rdoc.rdoc_dir = 'rdoc'
|
36
|
+
rdoc.title = "cardname #{VERSION}"
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class Cardname
|
2
|
+
module Contextual
|
3
|
+
RELATIVE_REGEXP = /\b_(left|right|whole|self|user|main|\d+|L*R?)\b/
|
4
|
+
|
5
|
+
def relative_name context_name
|
6
|
+
to_show(*context_name.to_name.parts).to_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def absolute_name context_name
|
10
|
+
to_absolute_name(context_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return true if name is left or right of context
|
14
|
+
def child_of? context
|
15
|
+
return false unless junction?
|
16
|
+
context_key = context.to_name.key
|
17
|
+
absolute_name(context).parent_keys.include? context_key
|
18
|
+
end
|
19
|
+
|
20
|
+
def relative?
|
21
|
+
s =~ RELATIVE_REGEXP || starts_with_joint?
|
22
|
+
end
|
23
|
+
|
24
|
+
def simple_relative?
|
25
|
+
relative? && stripped.to_name.starts_with_joint?
|
26
|
+
end
|
27
|
+
|
28
|
+
def absolute?
|
29
|
+
!relative?
|
30
|
+
end
|
31
|
+
|
32
|
+
def stripped
|
33
|
+
s.gsub RELATIVE_REGEXP, ""
|
34
|
+
end
|
35
|
+
|
36
|
+
def starts_with_joint?
|
37
|
+
length >= 2 && parts.first.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_show *ignore
|
41
|
+
ignore.map!(&:to_name)
|
42
|
+
|
43
|
+
show_parts = parts.map do |part|
|
44
|
+
reject = (part.empty? || (part =~ /^_/) || ignore.member?(part.to_name))
|
45
|
+
reject ? nil : part
|
46
|
+
end
|
47
|
+
|
48
|
+
show_name = show_parts.compact.to_name.s
|
49
|
+
|
50
|
+
case
|
51
|
+
when show_parts.compact.empty? then self
|
52
|
+
when show_parts[0].nil? then self.class.joint + show_name
|
53
|
+
else show_name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_absolute context, args={}
|
58
|
+
context = context.to_name
|
59
|
+
|
60
|
+
new_parts = replace_contextual_parts context
|
61
|
+
return "" if new_parts.empty?
|
62
|
+
|
63
|
+
if new_parts.first.empty? && !new_parts.to_name.starts_with?(context)
|
64
|
+
new_parts[0] = context.to_s
|
65
|
+
end
|
66
|
+
if new_parts.last.empty? && !new_parts.to_name.ends_with?(context)
|
67
|
+
new_parts[-1] = context.to_s
|
68
|
+
end
|
69
|
+
new_parts.join self.class.joint
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_absolute_name *args
|
73
|
+
self.class.new to_absolute(*args)
|
74
|
+
end
|
75
|
+
|
76
|
+
def nth_left n
|
77
|
+
# 1 = left; 2= left of left; 3 = left of left of left....
|
78
|
+
(n >= length ? parts[0] : parts[0..-n - 1]).to_name
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def replace_contextual_parts context
|
84
|
+
parts.map do |part|
|
85
|
+
new_part =
|
86
|
+
case part
|
87
|
+
when /^_user$/i
|
88
|
+
name_proc = self.class.session
|
89
|
+
name_proc ? name_proc.call : part
|
90
|
+
when /^_main$/i then self.class.params[:main_name]
|
91
|
+
when /^(_self|_whole|_)$/i then context.s
|
92
|
+
when /^_left$/i then context.trunk
|
93
|
+
# note - inconsistent use of left v. trunk
|
94
|
+
when /^_right$/i then context.tag
|
95
|
+
when /^_(\d+)$/i
|
96
|
+
pos = $~[1].to_i
|
97
|
+
pos = context.length if pos > context.length
|
98
|
+
context.parts[pos - 1]
|
99
|
+
when /^_(L*)(R?)$/i
|
100
|
+
l_s, r_s = $~[1].size, !$~[2].empty?
|
101
|
+
l_part = context.nth_left l_s
|
102
|
+
r_s ? l_part.tag : l_part.s
|
103
|
+
# when /^_/
|
104
|
+
# custom = args[:params] ? args[:params][part] : nil
|
105
|
+
# custom ? CGI.escapeHTML(custom) : part
|
106
|
+
# why are we escaping HTML here?
|
107
|
+
else
|
108
|
+
part
|
109
|
+
end.to_s.strip
|
110
|
+
new_part
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class Cardname
|
2
|
+
module Manipulate
|
3
|
+
# replace a subname
|
4
|
+
# keys are used for comparison
|
5
|
+
def replace old, new
|
6
|
+
old_name = old.to_name
|
7
|
+
new_name = new.to_name
|
8
|
+
return self if old_name.length > length
|
9
|
+
return replace_part(old_name, new_name) if old_name.simple?
|
10
|
+
return self unless include? old_name
|
11
|
+
replace_all_subsequences(old_name, new_name).to_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def replace_part oldpart, newpart
|
15
|
+
ensure_simpliness oldpart, "Use 'replace' to replace junctions"
|
16
|
+
|
17
|
+
oldpart = oldpart.to_name
|
18
|
+
newpart = newpart.to_name
|
19
|
+
|
20
|
+
parts.map do |p|
|
21
|
+
oldpart == p ? newpart : p
|
22
|
+
end.to_name
|
23
|
+
end
|
24
|
+
|
25
|
+
def replace_piece oldpiece, newpiece
|
26
|
+
oldpiece = oldpiece.to_name
|
27
|
+
newpiece = newpiece.to_name
|
28
|
+
|
29
|
+
return replace_part oldpiece, newpiece if oldpiece.simple?
|
30
|
+
return self unless self.starts_with?(oldpiece)
|
31
|
+
return newpiece if oldpiece.length == length
|
32
|
+
newpiece + self[oldpiece.length..-1]
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def replace_all_subsequences oldseq, newseq
|
38
|
+
res = []
|
39
|
+
i = 0
|
40
|
+
while i <= length - oldseq.length
|
41
|
+
# for performance reasons: check first character first then the rest
|
42
|
+
if oldseq.part_keys.first == part_keys[i] &&
|
43
|
+
oldseq.part_keys == part_keys[i, oldseq.length]
|
44
|
+
res += newseq.parts
|
45
|
+
i += oldseq.length
|
46
|
+
else
|
47
|
+
res << parts[i]
|
48
|
+
i += 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
res += parts[i..-1] if i < length
|
52
|
+
res
|
53
|
+
end
|
54
|
+
|
55
|
+
def ensure_simpliness part, msg=nil
|
56
|
+
return if part.to_name.simple?
|
57
|
+
raise StandardError, "'#{part}' has to be simple. #{msg}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# ~~~~~~~~~~~~~~~~~~~~ MISC ~~~~~~~~~~~~~~~~~~~~
|
62
|
+
|
63
|
+
# HACK. This doesn't belong here.
|
64
|
+
# shouldn't it use inclusions???
|
65
|
+
def self.substitute! str, hash
|
66
|
+
hash.keys.each do |var|
|
67
|
+
str.gsub! var_re do |x|
|
68
|
+
hash[var.to_sym]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
str
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
class Cardname
|
2
|
+
# naming conventions:
|
3
|
+
# methods that end with _name return name objects
|
4
|
+
# the same methods without _name return strings
|
5
|
+
module Parts
|
6
|
+
attr_reader :parts, :part_keys, :simple
|
7
|
+
|
8
|
+
alias simple? simple
|
9
|
+
alias_method :to_a, :parts
|
10
|
+
|
11
|
+
def initialize_parts
|
12
|
+
# -1 = don't suppress trailing null fields
|
13
|
+
@parts = @s.split(/\s*#{JOINT_RE}\s*/, -1)
|
14
|
+
@simple = @parts.size <= 1
|
15
|
+
# simple check needed to avoid inifinite recursion
|
16
|
+
@part_keys =
|
17
|
+
@simple ? [simple_key] : @parts.map { |p| p.to_name.simple_key }
|
18
|
+
end
|
19
|
+
|
20
|
+
def left
|
21
|
+
@left ||= simple? ? nil : parts[0..-2] * self.class.joint
|
22
|
+
end
|
23
|
+
|
24
|
+
def right
|
25
|
+
@right ||= simple? ? nil : parts[-1]
|
26
|
+
end
|
27
|
+
|
28
|
+
def left_name
|
29
|
+
@left_name ||= left && self.class.new(left)
|
30
|
+
end
|
31
|
+
|
32
|
+
def right_name
|
33
|
+
@right_name ||= right && self.class.new(right)
|
34
|
+
end
|
35
|
+
|
36
|
+
def left_key
|
37
|
+
@left_key ||= simple? ? nil : part_keys[0..-2] * self.class.joint
|
38
|
+
end
|
39
|
+
|
40
|
+
def right_key
|
41
|
+
@right_key ||= simple? ? nil : part_keys.last
|
42
|
+
end
|
43
|
+
|
44
|
+
def parents
|
45
|
+
@parents ||= junction? ? [left, right] : []
|
46
|
+
end
|
47
|
+
|
48
|
+
def parent_names
|
49
|
+
@parent_names ||= junction? ? [left_name, right_name] : []
|
50
|
+
end
|
51
|
+
|
52
|
+
def parent_keys
|
53
|
+
@parent_keys ||= junction? ? [left_key, right_key] : []
|
54
|
+
end
|
55
|
+
|
56
|
+
# Note that all names have a trunk and tag,
|
57
|
+
# but only junctions have left and right
|
58
|
+
|
59
|
+
def trunk
|
60
|
+
@trunk ||= simple? ? s : left
|
61
|
+
end
|
62
|
+
|
63
|
+
def tag
|
64
|
+
@tag ||= simple? ? s : right
|
65
|
+
end
|
66
|
+
|
67
|
+
def trunk_name
|
68
|
+
@trunk_name ||= simple? ? self : left_name
|
69
|
+
end
|
70
|
+
|
71
|
+
def tag_name
|
72
|
+
@tag_name ||= simple? ? self : right_name
|
73
|
+
end
|
74
|
+
|
75
|
+
def part_names
|
76
|
+
@part_names ||= parts.map(&:to_name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def piece_names
|
80
|
+
@piece_names ||= pieces.map(&:to_name)
|
81
|
+
end
|
82
|
+
|
83
|
+
# self and all ancestors (= parts and recursive lefts)
|
84
|
+
# @example
|
85
|
+
# "A+B+C+D".to_name.pieces
|
86
|
+
# # => ["A", "B", "C", "D", "A+B", "A+B+C", "A+B+C+D"]
|
87
|
+
def pieces
|
88
|
+
@pieces ||=
|
89
|
+
if simple?
|
90
|
+
[self]
|
91
|
+
else
|
92
|
+
junction_pieces = []
|
93
|
+
parts[1..-1].inject parts[0] do |left, right|
|
94
|
+
piece = [left, right] * self.class.joint
|
95
|
+
junction_pieces << piece
|
96
|
+
piece
|
97
|
+
end
|
98
|
+
parts + junction_pieces
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def + other
|
103
|
+
self.class.new(parts + other.to_name.parts)
|
104
|
+
end
|
105
|
+
|
106
|
+
def [] *args
|
107
|
+
self.class.new parts[*args]
|
108
|
+
end
|
109
|
+
|
110
|
+
# full support of array methods caused trouble with `flatten` calls
|
111
|
+
# It splits the parts of cardnames in arrays
|
112
|
+
# # name parts can be accessed and manipulated like an array
|
113
|
+
# def method_missing method, *args, &block
|
114
|
+
# if ARRAY_METHODS.include? method # parts.respond_to?(method)
|
115
|
+
# self.class.new parts.send(method, *args, &block)
|
116
|
+
# else
|
117
|
+
# super
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# def respond_to? method, include_private=false
|
122
|
+
# return true if ARRAY_METHODS.include? method
|
123
|
+
# super || parts.respond_to?(method, include_private)
|
124
|
+
# end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Cardname
|
2
|
+
module Predicates
|
3
|
+
# @return true if name has more than one part
|
4
|
+
def junction?
|
5
|
+
!simple?
|
6
|
+
end
|
7
|
+
|
8
|
+
def blank?
|
9
|
+
s.blank?
|
10
|
+
end
|
11
|
+
alias empty? blank?
|
12
|
+
|
13
|
+
def valid?
|
14
|
+
!parts.find do |pt|
|
15
|
+
pt.match self.class.banned_re
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return true if name starts with the same parts as `prefix`
|
20
|
+
def starts_with? prefix
|
21
|
+
start_name = prefix.to_name
|
22
|
+
start_name == self[0, start_name.length]
|
23
|
+
end
|
24
|
+
alias_method :start_with?, :starts_with?
|
25
|
+
|
26
|
+
# @return true if name ends with the same parts as `prefix`
|
27
|
+
def ends_with? postfix
|
28
|
+
end_name = postfix.to_name
|
29
|
+
end_name == self[-end_name.length..-1]
|
30
|
+
end
|
31
|
+
alias_method :end_with?, :ends_with?
|
32
|
+
|
33
|
+
# @return true if name has a chain of parts that equals `subname`
|
34
|
+
def include? subname
|
35
|
+
subkey = subname.to_name.key
|
36
|
+
key =~ /(^|#{JOINT_RE})#{Regexp.quote subkey}($|#{JOINT_RE})/
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Cardname
|
2
|
+
module Variants
|
3
|
+
def simple_key
|
4
|
+
return "" if @s.empty?
|
5
|
+
decoded
|
6
|
+
.underscore
|
7
|
+
.gsub(/[^#{OK4KEY_RE}]+/, '_')
|
8
|
+
.split(/_+/)
|
9
|
+
.reject(&:empty?)
|
10
|
+
.map { |key| Cardname.stable_uninflect(key) }
|
11
|
+
.join('_')
|
12
|
+
end
|
13
|
+
|
14
|
+
def url_key
|
15
|
+
@url_key ||= part_names.map do |part_name|
|
16
|
+
stripped = part_name.decoded.gsub(/[^#{OK4KEY_RE}]+/, ' ').strip
|
17
|
+
stripped.gsub(/[\s\_]+/, '_')
|
18
|
+
end * self.class.joint
|
19
|
+
end
|
20
|
+
|
21
|
+
# safe to be used in HTML as id ('*' and '+' are not allowed),
|
22
|
+
# but the key is no longer unique.
|
23
|
+
# For example "A-XB" and "A+*B" have the same safe_key
|
24
|
+
def safe_key
|
25
|
+
@safe_key ||= key.tr('*', 'X').tr self.class.joint, '-'
|
26
|
+
end
|
27
|
+
|
28
|
+
def decoded
|
29
|
+
@decoded ||= s.index('&') ? HTMLEntities.new.decode(s) : s
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_sym
|
33
|
+
s.to_sym
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/cardname.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'active_support/configurable'
|
4
|
+
require 'active_support/inflector'
|
5
|
+
require 'htmlentities'
|
6
|
+
require_relative 'cardname/parts'
|
7
|
+
require_relative 'cardname/variants'
|
8
|
+
require_relative 'cardname/contextual'
|
9
|
+
require_relative 'cardname/predicates'
|
10
|
+
require_relative 'cardname/manipulate'
|
11
|
+
|
12
|
+
class Cardname < Object
|
13
|
+
|
14
|
+
include Parts
|
15
|
+
include Variants
|
16
|
+
include Contextual
|
17
|
+
include Predicates
|
18
|
+
include Manipulate
|
19
|
+
|
20
|
+
RUBYENCODING = RUBY_VERSION !~ /^1\.8/
|
21
|
+
OK4KEY_RE = RUBYENCODING ? '\p{Word}\*' : '\w\*'
|
22
|
+
|
23
|
+
include ActiveSupport::Configurable
|
24
|
+
|
25
|
+
config_accessor :joint, :banned_array, :var_re, :uninflect, :params,
|
26
|
+
:session, :stabilize
|
27
|
+
|
28
|
+
Cardname.joint = '+'
|
29
|
+
Cardname.banned_array = ['/', '~', '|']
|
30
|
+
Cardname.var_re = /\{([^\}]*\})\}/
|
31
|
+
Cardname.uninflect = :singularize
|
32
|
+
Cardname.stabilize = false
|
33
|
+
|
34
|
+
JOINT_RE = Regexp.escape joint
|
35
|
+
|
36
|
+
@@name2nameobject = {} # name cache
|
37
|
+
|
38
|
+
class << self
|
39
|
+
def new obj
|
40
|
+
return obj if obj.is_a? self.class
|
41
|
+
str = stringify obj
|
42
|
+
known_name(str) || super(str.strip)
|
43
|
+
end
|
44
|
+
|
45
|
+
def known_name str
|
46
|
+
@@name2nameobject[str]
|
47
|
+
end
|
48
|
+
|
49
|
+
def stringify obj
|
50
|
+
if obj.is_a?(Array)
|
51
|
+
obj.map(&:to_s) * joint
|
52
|
+
else
|
53
|
+
obj.to_s
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def banned_re
|
58
|
+
%r{#{ (['['] + banned_array << joint) * '\\' + ']' }}
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sometimes the core rule "the key's key must be itself" (called "stable" below) is violated
|
62
|
+
# eg. it fails with singularize as uninflect method for Matthias -> Matthia -> Matthium
|
63
|
+
# Usually that means the name is a proper noun and not a plural.
|
64
|
+
# You can choose between two solutions:
|
65
|
+
# 1. don't uninflect if the uninflected key is not stable (stabilize = false)
|
66
|
+
# (probably the best choice because you want Matthias not to be the same as Matthium)
|
67
|
+
# 2. uninflect until the key is stable (stabilize = true)
|
68
|
+
def stable_uninflect name
|
69
|
+
key_one = name.send(Cardname.uninflect)
|
70
|
+
key_two = key_one.send(Cardname.uninflect)
|
71
|
+
return key_one unless key_one != key_two
|
72
|
+
Cardname.stabilize ? stable_uninflect(key_two) : name
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
77
|
+
# ~~~~~~~~~~~~~~~~~~~~~~ INSTANCE ~~~~~~~~~~~~~~~~~~~~~~~~~
|
78
|
+
attr_reader :key, :s
|
79
|
+
alias to_s s
|
80
|
+
|
81
|
+
def initialize str
|
82
|
+
@s = str.to_s.strip
|
83
|
+
@s = @s.encode('UTF-8') if RUBYENCODING
|
84
|
+
initialize_parts
|
85
|
+
@key = @part_keys.join(self.class.joint)
|
86
|
+
@@name2nameobject[str] = self
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_name
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
def length
|
94
|
+
parts.length
|
95
|
+
end
|
96
|
+
|
97
|
+
def size
|
98
|
+
to_s.size
|
99
|
+
end
|
100
|
+
|
101
|
+
def inspect
|
102
|
+
"<#{self.class.name} key=#{key}[#{self}]>"
|
103
|
+
end
|
104
|
+
|
105
|
+
def == other
|
106
|
+
other_key =
|
107
|
+
case
|
108
|
+
when other.respond_to?(:key) then other.key
|
109
|
+
when other.respond_to?(:to_name) then other.to_name.key
|
110
|
+
else other.to_s
|
111
|
+
end
|
112
|
+
other_key == key
|
113
|
+
end
|
114
|
+
end
|
data/lib/core_ext.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cardname
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerry Gleason
|
8
|
+
- Ethan McCutchen
|
9
|
+
- Philipp Kühl
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2017-08-02 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '5.1'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '5.1'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: htmlentities
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '4.3'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '4.3'
|
43
|
+
description: Naming patterns abstracted from Decko cards
|
44
|
+
email: info@decko.org
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files:
|
48
|
+
- README.rdoc
|
49
|
+
files:
|
50
|
+
- Gemfile
|
51
|
+
- Gemfile.lock
|
52
|
+
- README.rdoc
|
53
|
+
- Rakefile
|
54
|
+
- lib/cardname.rb
|
55
|
+
- lib/cardname/contextual.rb
|
56
|
+
- lib/cardname/manipulate.rb
|
57
|
+
- lib/cardname/parts.rb
|
58
|
+
- lib/cardname/predicates.rb
|
59
|
+
- lib/cardname/variants.rb
|
60
|
+
- lib/core_ext.rb
|
61
|
+
homepage: http://decko.org
|
62
|
+
licenses:
|
63
|
+
- GPL-2.0
|
64
|
+
- GPL-3.0
|
65
|
+
metadata: {}
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- "--main"
|
69
|
+
- README.rdoc
|
70
|
+
- "--inline-source"
|
71
|
+
- "--line-numbers"
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.6.6
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Card names without all the cards
|
90
|
+
test_files: []
|