cardname 0.1
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.
- 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: []
|