cardname 0.15.0 → 0.15.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09f8f18762c861c7f86ba80f9b3f880c4eed7b44b469d01db78433fbe50db63f'
4
- data.tar.gz: 32b9b34f0b2bf444ce301876703f7cb0a45822e64cbf7142731828b09d282f98
3
+ metadata.gz: 8e2d34cf377f12ca3338cb56f35c78b241d910ef69d310a815eb689a5b0b668a
4
+ data.tar.gz: 5e63e52714e373cb06e6dbcf4f411554e3eaa04948774a7e650b33824d50764d
5
5
  SHA512:
6
- metadata.gz: e9dbdb672ab542bdbf618cd72ed6819f72d469a0a1a0f0ba1d1799977dd66ef21b46e0034b9846948585696ecdca7abbe94811ad18cd9e9d69fe106840c6e6ea
7
- data.tar.gz: 840efe97c1f02b061445c9ed8b82b01f04be25c95fe3cdd90da46d3acf5d111be9090ba24d8cc499808d17f762c87a5c3100ee4440e4bb94e7f2f3fb7f094184
6
+ metadata.gz: a558685490a65580dc8288c8e6e37cfa85631d6ac8d298c806c16d88c915364777f92ace7d1c2d77fee427862576b2440e28ab6abe9bfc6ded96c94841eca0de
7
+ data.tar.gz: faebb45833cc3aec5d7c1ef1a93c3bc65ba0e5cfd77f7deebf653e933e7244df6ac7f8416c7c1b49f6c2b8ff47e711a65cf0116c2956b10f8edc40bc19035544
@@ -0,0 +1,60 @@
1
+ class Cardname
2
+ # methods for the Cardname class.
3
+ module ClassMethods
4
+ # #new skips installation and returns a cached Cardname object when possible
5
+ # @return [Cardname]
6
+ def new obj
7
+ return obj if obj.is_a? self.class
8
+
9
+ str = stringify(obj)
10
+ cache[str] ||= super(str)
11
+ end
12
+
13
+ # Cardname cache. keys are strings, values are corresponding Cardname objects
14
+ # Note that unlike most decko/card caches, the cardname cache is process-specific
15
+ # and should not need to be reset even with data changes, because Cardname objects
16
+ # are not data-aware.
17
+ #
18
+ # @return [Hash]
19
+ def cache
20
+ @cache ||= {}
21
+ end
22
+
23
+ # reset Cardname cache
24
+ # @see #cache
25
+ # @return [Hash]
26
+ def reset
27
+ @cache = {}
28
+ end
29
+
30
+ # true if there are no banned characters
31
+ # @return [Boolean]
32
+ def nothing_banned?
33
+ return @nothing_banned unless @nothing_banned.nil?
34
+
35
+ @nothing_banned = banned_array.empty?
36
+ end
37
+
38
+ # regular expression for detecting banned characters
39
+ # @return [Regexp]
40
+ def banned_re
41
+ @banned_re ||= /[#{Regexp.escape((banned_array + [joint])).join}]/
42
+ end
43
+
44
+ # split string on joint into parts
45
+ # @return [Array]
46
+ def split_parts str
47
+ str.split(/\s*#{JOINT_RE}\s*/, -1)
48
+ end
49
+
50
+ private
51
+
52
+ def stringify obj
53
+ if obj.is_a?(Array)
54
+ obj.map(&:to_s) * joint
55
+ else
56
+ obj.to_s
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,8 +1,9 @@
1
1
  class Cardname
2
+ # contextual (or relative) names are names that vary by context
2
3
  module Contextual
3
4
  RELATIVE_REGEXP = /\b_(left|right|whole|self|user|main|\d+|L*R?)\b/
4
5
 
5
- # @return true if name is left or right of context
6
+ # @return [Boolean] true if name is left or right of context
6
7
  def child_of? context
7
8
  return false unless compound?
8
9
 
@@ -10,22 +11,31 @@ class Cardname
10
11
  absolute_name(context).parent_keys.include? context_key
11
12
  end
12
13
 
14
+ # @return [Boolean]
13
15
  def relative?
14
16
  starts_with_joint? || (s =~ RELATIVE_REGEXP).present?
15
17
  end
16
18
 
19
+ # starts with joint, no other contextual element
20
+ # @return [Boolean]
17
21
  def simple_relative?
18
22
  starts_with_joint? && (s =~ RELATIVE_REGEXP).nil?
19
23
  end
20
24
 
25
+ # not relative
26
+ # @return [Boolean]
21
27
  def absolute?
22
28
  !relative?
23
29
  end
24
30
 
31
+ # contextual elements removed
32
+ # @return [String]
25
33
  def stripped
26
34
  s.gsub RELATIVE_REGEXP, ""
27
35
  end
28
36
 
37
+ # +X
38
+ # @return [Boolean]
29
39
  def starts_with_joint?
30
40
  compound? && parts.first.empty?
31
41
  end
@@ -44,22 +54,46 @@ class Cardname
44
54
  key == compressed.absolute_name(from).key ? compressed : self
45
55
  end
46
56
 
47
- def remove_context *from
48
- return false unless from.compact.present?
57
+ # @return [String]
58
+ def absolute context
59
+ context = (context || "").to_name
60
+ new_parts = absolutize_contextual_parts context
61
+ return "" if new_parts.empty?
49
62
 
50
- remaining = parts_excluding(*from)
51
- return false if remaining.compact.empty? || # all name parts in context
52
- remaining == parts # no name parts in context
63
+ absolutize_extremes new_parts, context.s
64
+ new_parts.join self.class.joint
65
+ end
53
66
 
54
- remaining
67
+ # @return [Cardname]
68
+ def absolute_name *args
69
+ absolute(*args).to_name
70
+ end
71
+
72
+ # 1 = left; 2= left of left; 3 = left of left of left....
73
+ # @return [Cardname]
74
+ def nth_left_name n
75
+ (n >= length ? parts[0] : parts[0..-n - 1]).to_name
55
76
  end
56
77
 
78
+ private
79
+
57
80
  def parts_excluding *string
58
81
  exclude_name = string.to_name
59
82
  exclude_keys = exclude_name ? exclude_name.part_names.map(&:key) : []
60
83
  parts_minus exclude_keys
61
84
  end
62
85
 
86
+ def remove_context *from
87
+ return false unless from.compact.present?
88
+
89
+ remaining = parts_excluding(*from)
90
+ return false if remaining.compact.empty? || # all name parts in context
91
+ remaining == parts # no name parts in context
92
+
93
+ remaining
94
+ end
95
+
96
+ # @return [Array <String>]
63
97
  def parts_minus keys_to_ignore
64
98
  parts.map do |part|
65
99
  next if part.empty?
@@ -70,26 +104,6 @@ class Cardname
70
104
  end
71
105
  end
72
106
 
73
- def absolute context
74
- context = (context || "").to_name
75
- new_parts = absolutize_contextual_parts context
76
- return "" if new_parts.empty?
77
-
78
- absolutize_extremes new_parts, context.s
79
- new_parts.join self.class.joint
80
- end
81
-
82
- def absolute_name *args
83
- absolute(*args).to_name
84
- end
85
-
86
- def nth_left n
87
- # 1 = left; 2= left of left; 3 = left of left of left....
88
- (n >= length ? parts[0] : parts[0..-n - 1]).to_name
89
- end
90
-
91
- private
92
-
93
107
  def absolutize_contextual_parts context
94
108
  parts.map do |part|
95
109
  case part
@@ -118,7 +132,7 @@ class Cardname
118
132
  def partmap_part match, context
119
133
  l_s = match[1].size
120
134
  r_s = !match[2].empty?
121
- l_part = context.nth_left l_s
135
+ l_part = context.nth_left_name l_s
122
136
  r_s ? l_part.tag : l_part.s
123
137
  end
124
138
 
@@ -1,52 +1,47 @@
1
1
  class Cardname
2
+ # methods for altering name
2
3
  module Manipulate
3
- # swap a subname
4
- # keys are used for comparison
5
- def swap old, new
6
- old_name = old.to_name
7
- new_name = new.to_name
8
- return self if old_name.num_parts > num_parts
9
- return swap_part(old_name, new_name) if old_name.simple?
10
- return self unless include? old_name
11
-
12
- swap_all_subsequences(old_name, new_name).to_name
4
+ # alter cardname based on card index
5
+ # @return [Cardname]
6
+ def []= index, val
7
+ p = parts
8
+ p[index] = val
9
+ replace self.class.new(p)
13
10
  end
14
11
 
15
- def swap_part oldpart, newpart
16
- ensure_simpleness oldpart, "Use 'swap' to swap junctions"
17
-
18
- oldpart = oldpart.to_name
19
- newpart = newpart.to_name
20
-
21
- parts.map do |p|
22
- oldpart == p ? newpart : p
23
- end.to_name
12
+ # append part to cardname
13
+ # @return [Cardname]
14
+ def << val
15
+ replace self.class.new(parts << val)
24
16
  end
25
17
 
26
- def swap_piece oldpiece, newpiece
27
- oldpiece = oldpiece.to_name
28
- newpiece = newpiece.to_name
29
-
30
- return swap_part oldpiece, newpiece if oldpiece.simple?
31
- return self unless starts_with_parts?(oldpiece)
32
- return newpiece if oldpiece.num_parts == num_parts
33
-
34
- self.class.new [newpiece, self[oldpiece.num_parts..-1]].flatten
35
- end
36
-
37
- def num_parts
38
- parts.length
39
- end
18
+ # swap one name for another (keys are used for comparison)
19
+ # @return [Cardname]
20
+ def swap old, new
21
+ old_name = old.to_name
22
+ new_name = new.to_name
40
23
 
41
- def [] *args
42
- self.class.new part_names[*args]
24
+ if old_name.num_parts > num_parts
25
+ self
26
+ elsif old_name.simple?
27
+ swap_part old_name, new_name
28
+ elsif include? old_name
29
+ swap_all_subsequences(old_name, new_name).to_name
30
+ else
31
+ self
32
+ end
43
33
  end
44
34
 
35
+ # add a joint to name's beginning (if it doesn't already start with one)
36
+ # @return [String]
45
37
  def prepend_joint
46
38
  joint = self.class.joint
47
39
  self =~ /^#{Regexp.escape joint}/ ? self : (joint + self)
48
40
  end
41
+ alias_method :to_field, :prepend_joint
49
42
 
43
+ # substitute name, where it appears in str, with new string
44
+ # @return [String]
50
45
  def sub_in str, with:
51
46
  %i[capitalize downcase].product(%i[pluralize singularize])
52
47
  .inject(str) do |s, (m1, m2)|
@@ -54,10 +49,12 @@ class Cardname
54
49
  end
55
50
  end
56
51
 
57
- alias_method :to_field, :prepend_joint
58
-
59
52
  private
60
53
 
54
+ def swap_part oldpart, newpart
55
+ parts.map { |p| oldpart == p ? newpart : p }.to_name
56
+ end
57
+
61
58
  def swap_all_subsequences oldseq, newseq
62
59
  res = []
63
60
  i = 0
@@ -75,11 +72,5 @@ class Cardname
75
72
  res += parts[i..-1] if i < num_parts
76
73
  res
77
74
  end
78
-
79
- def ensure_simpleness part, msg=nil
80
- return if part.to_name.simple?
81
-
82
- raise StandardError, "'#{part}' has to be simple. #{msg}"
83
- end
84
75
  end
85
76
  end
@@ -1,82 +1,156 @@
1
1
  class Cardname
2
2
  # naming conventions:
3
- # methods that end with _name return name objects
4
- # the same methods without _name return strings
3
+ #
4
+ # - methods that end with _name return {Cardname} objects
5
+ # - methods that end with _key return {Cardname#key case/space keys}
6
+ # - methods without _name or _key return Strings
7
+ #
5
8
  module Parts
6
- # PARTS
7
- def part_names
8
- @part_names ||= generate_part_names
9
+ # the part of a compound name to the left of the rightmost joint.
10
+ # @example
11
+ # "A".cardname.left -> nil
12
+ # "A+B".cardname.left -> "A"
13
+ # "A+B+C".cardname.left -> "A+B"
14
+ # "A+B+C+D".cardname.left -> "A+B+C"
15
+ # @see #trunk
16
+ # @return [String]
17
+ def left
18
+ left_name&.s
19
+ end
20
+
21
+ # @see #left
22
+ # @return [String]
23
+ def left_key
24
+ left_name&.key
25
+ end
26
+
27
+ # @see #left
28
+ # @return [Cardname]
29
+ def left_name
30
+ simple? ? nil : self.class.new(part_names[0..-2])
31
+ end
32
+
33
+ # for compound cards, an array of the left and right
34
+ # @example
35
+ # "A".cardname.parents -> []
36
+ # "A+B".cardname.parents -> ["A", "B"]
37
+ # "A+B+C".cardname.parents -> ["A+B", "C"]
38
+ # "A+B+C+D".cardname.parents -> ["A+B+C", "D"]
39
+ # @see #parts
40
+ # @return [Array <String>]
41
+ def parents
42
+ parent_names.map(&:s)
9
43
  end
10
44
 
45
+ # @see #parents
46
+ # @return [Array <String>]
47
+ def parent_keys
48
+ parent_names.map(&:key)
49
+ end
50
+
51
+ # @see #parents
52
+ # @return [Array <Cardname>]
53
+ def parent_names
54
+ simple? ? [] : [left_name, right_name]
55
+ end
56
+
57
+ # for compound cards, each joint separated part
58
+ # @example
59
+ # "A".cardname.parts -> []
60
+ # "A+B".cardname.parts -> ["A", "B"]
61
+ # "A+B+C".cardname.parts -> ["A", "B", "C"]
62
+ # "A+B+C+D".cardname.parts -> ["A", "B", C", "D"]
63
+ # @see #parents
64
+ # @return [Array <String>]
11
65
  def parts
12
66
  part_names.map(&:s)
13
67
  end
14
68
  alias_method :to_a, :parts
15
69
 
70
+ # @see #parts
71
+ # @return [Array <String>]
16
72
  def part_keys
17
73
  part_names.map(&:key)
18
74
  end
19
75
 
20
- def trunk_name
21
- simple? ? self : left_name
76
+ # @see #parts
77
+ # @return [Array <Cardname>]
78
+ def part_names
79
+ @part_names ||= generate_part_names
22
80
  end
23
81
 
82
+ # like #left, but returns self for simple cards
83
+ # @example
84
+ # "A".cardname.trunk -> "A"
85
+ # "A+B".cardname.trunk -> "A"
86
+ # "A+B+C".cardname.trunk -> "A+B"
87
+ # "A+B+C+D".cardname.trunk -> "A+B+C"
88
+ # @see #left
89
+ # @return [String]
24
90
  def trunk
25
91
  trunk_name.s
26
92
  end
27
93
 
94
+ # @see #trunk
95
+ # @return [String]
28
96
  def trunk_key
29
97
  trunk_name.key
30
98
  end
31
99
 
32
- def tag_name
33
- simple? ? self : right_name
100
+ # @see #trunk
101
+ # @return [Cardname]
102
+ def trunk_name
103
+ simple? ? self : left_name
34
104
  end
35
105
 
106
+ # like #right, but returns self for simple cards
107
+ # @see #right
108
+ # @example
109
+ # "A".cardname.tag -> "A"
110
+ # "A+B".cardname.tag -> "B"
111
+ # "A+B+C".cardname.tag -> "C"
112
+ # "A+B+C+D".cardname.tag -> "D"
113
+ # @return [String]
36
114
  def tag
37
115
  tag_name.s
38
116
  end
39
117
 
118
+ # @see #tag
119
+ # @return [String]
40
120
  def tag_key
41
121
  tag_name.key
42
122
  end
43
123
 
44
- def parent_names
45
- simple? ? [] : [left_name, right_name]
46
- end
47
-
48
- def parents
49
- parent_names.map(&:s)
50
- end
51
-
52
- def parent_keys
53
- parent_names.map(&:key)
54
- end
55
-
56
- def left_name
57
- simple? ? nil : self.class.new(part_names[0..-2])
58
- end
59
-
60
- def left
61
- left_name&.s
62
- end
63
-
64
- def left_key
65
- left_name&.key
66
- end
67
-
68
- def right_name
69
- simple? ? nil : part_names[-1]
124
+ # @see #tag
125
+ # @return [Cardname]
126
+ def tag_name
127
+ simple? ? self : right_name
70
128
  end
71
129
 
130
+ # the part of a compound name to the left of the rightmost joint.
131
+ #
132
+ # "A".cardname.right -> nil
133
+ # "A+B".cardname.right -> "B"
134
+ # "A+B+C".cardname.right -> "C"
135
+ # "A+B+C+D".cardname.right -> "D"
136
+ # @see #tag
137
+ # @return [String]
72
138
  def right
73
139
  right_name&.s
74
140
  end
75
141
 
142
+ # @see #right
143
+ # @return [String]
76
144
  def right_key
77
145
  right_name&.key
78
146
  end
79
147
 
148
+ # @see #right
149
+ # @return [Cardname]
150
+ def right_name
151
+ simple? ? nil : part_names[-1]
152
+ end
153
+
80
154
  private
81
155
 
82
156
  def generate_part_names
@@ -5,23 +5,35 @@ class Cardname
5
5
  module Pieces
6
6
  # self and all ancestors (= parts and recursive lefts)
7
7
  # @example
8
- # "A+B+C+D".to_name.pieces
9
- # # => ["A", "B", "C", "D", "A+B", "A+B+C", "A+B+C+D"]
8
+ # "A+B+C+D".to_name.pieces => ["A", "B", "C", "D", "A+B", "A+B+C", "A+B+C+D"]
9
+ # @return [Array <String>]
10
10
  def pieces
11
- simple? ? [self] : (parts + junction_pieces)
11
+ simple? ? [self] : (parts + compound_pieces)
12
12
  end
13
13
 
14
+ # @see #pieces
15
+ # @return [Array <Cardname>]
14
16
  def piece_names
15
17
  pieces.map(&:to_name)
16
18
  end
17
19
 
20
+ # parents, parents' parents, etc
21
+ # @example
22
+ # "A+B+C+D".to_name.ancestors => ["A", "B", "C", "D", "A+B", "A+B+C"]
23
+ # @return [Array <String>]
18
24
  def ancestors
19
25
  pieces.reject { |p| p == self }
20
26
  end
21
27
 
28
+ # @see #ancestors
29
+ # @return [Array <Cardname>]
30
+ def ancestor_pieces
31
+ ancestors.map(&:to_name)
32
+ end
33
+
22
34
  private
23
35
 
24
- def junction_pieces
36
+ def compound_pieces
25
37
  [].tap do |pieces|
26
38
  parts[1..-1].inject parts[0] do |left, right|
27
39
  piece = [left, right] * self.class.joint
@@ -1,16 +1,18 @@
1
1
  class Cardname
2
+ # name methods returning true/false
2
3
  module Predicates
3
- # @return true if name has only one part
4
+ # @return [Boolean] true if name has only one part
4
5
  def simple?
5
6
  part_names if @simple.nil?
6
7
  @simple
7
8
  end
8
9
 
9
- # @return true if name has more than one part
10
+ # @return [Boolean] true if name has more than one part
10
11
  def compound?
11
12
  !simple?
12
13
  end
13
14
 
15
+ # @return [Boolean] true unless name contains banned characters
14
16
  def valid?
15
17
  return true if self.class.nothing_banned?
16
18
 
@@ -19,21 +21,21 @@ class Cardname
19
21
  end
20
22
  end
21
23
 
22
- # @return true if name starts with the same parts as `prefix`
24
+ # @return [Boolean] true if name starts with the same parts as `prefix`
23
25
  def starts_with_parts? *prefix
24
26
  start_name = prefix.to_name
25
27
  start_name == self[0, start_name.num_parts]
26
28
  end
27
29
  alias_method :start_with_parts?, :starts_with_parts?
28
30
 
29
- # @return true if name ends with the same parts as `prefix`
31
+ # @return [Boolean] true if name ends with the same parts as `prefix`
30
32
  def ends_with_parts? *suffix
31
33
  end_name = suffix.to_name
32
34
  end_name == self[-end_name.num_parts..-1]
33
35
  end
34
36
  alias_method :end_with_parts?, :ends_with_parts?
35
37
 
36
- # @return true if name has a chain of parts that equals `subname`
38
+ # @return [Boolean] true if name has a chain of parts that equals `subname`
37
39
  def include? subname
38
40
  subkey = subname.to_name.key
39
41
  key =~ /(^|#{JOINT_RE})#{Regexp.quote subkey}($|#{JOINT_RE})/
@@ -2,6 +2,7 @@ require "htmlentities"
2
2
 
3
3
  class Cardname
4
4
  module Variants
5
+ # @return [String]
5
6
  def simple_key
6
7
  return "" if empty?
7
8
 
@@ -14,6 +15,8 @@ class Cardname
14
15
  .join("_")
15
16
  end
16
17
 
18
+ # URI-friendly version of name. retains case, underscores for space
19
+ # @return [String]
17
20
  def url_key
18
21
  part_names.map do |part_name|
19
22
  stripped = part_name.decoded.gsub(/[^#{OK4KEY_RE}]+/, " ").strip
@@ -24,18 +27,16 @@ class Cardname
24
27
  # safe to be used in HTML as id ('*' and '+' are not allowed),
25
28
  # but the key is no longer unique.
26
29
  # For example "A-XB" and "A+*B" have the same safe_key
30
+ # @return [String]
27
31
  def safe_key
28
32
  key.tr("*", "X").tr self.class.joint, "-"
29
33
  end
30
34
 
35
+ # @return [String]
31
36
  def decoded
32
37
  @decoded ||= s.index("&") ? HTMLEntities.new.decode(s) : s
33
38
  end
34
39
 
35
- def to_sym
36
- s.to_sym
37
- end
38
-
39
40
  private
40
41
 
41
42
  def uninflect_method
data/lib/cardname.rb CHANGED
@@ -3,6 +3,10 @@
3
3
  require "active_support/inflector"
4
4
  require "htmlentities"
5
5
 
6
+ # The Cardname class generalizes the core naming concepts of Decko/Card. The most central
7
+ # of these is the idea that compound names can be formed by combining simple names.
8
+ #
9
+ #
6
10
  class Cardname < String
7
11
  require "cardname/parts"
8
12
  require "cardname/pieces"
@@ -11,6 +15,7 @@ class Cardname < String
11
15
  require "cardname/predicates"
12
16
  require "cardname/manipulate"
13
17
  require "cardname/fields"
18
+ require "cardname/class_methods"
14
19
 
15
20
  include Parts
16
21
  include Pieces
@@ -19,8 +24,7 @@ class Cardname < String
19
24
  include Predicates
20
25
  include Manipulate
21
26
  include Fields
22
-
23
- OK4KEY_RE = '\p{Word}\*'
27
+ extend ClassMethods
24
28
 
25
29
  cattr_accessor :joint, :banned_array, :var_re, :uninflect, :params, :session, :stabilize
26
30
 
@@ -30,49 +34,9 @@ class Cardname < String
30
34
  self.uninflect = :singularize
31
35
  self.stabilize = false
32
36
 
37
+ OK4KEY_RE = '\p{Word}\*'
33
38
  JOINT_RE = Regexp.escape joint
34
39
 
35
- class << self
36
- def new obj
37
- return obj if obj.is_a? self.class
38
-
39
- str = stringify(obj)
40
- cache[str] ||= super(str)
41
- end
42
-
43
- def reset
44
- @cache = {}
45
- end
46
-
47
- def nothing_banned?
48
- return @nothing_banned unless @nothing_banned.nil?
49
-
50
- @nothing_banned = banned_array.empty?
51
- end
52
-
53
- def banned_re
54
- @banned_re ||= /[#{Regexp.escape((banned_array + [joint])).join}]/
55
- end
56
-
57
- def split_parts str
58
- str.split(/\s*#{JOINT_RE}\s*/, -1)
59
- end
60
-
61
- def cache
62
- @cache ||= {}
63
- end
64
-
65
- private
66
-
67
- def stringify obj
68
- if obj.is_a?(Array)
69
- obj.map(&:to_s) * joint
70
- else
71
- obj.to_s
72
- end
73
- end
74
- end
75
-
76
40
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77
41
  # ~~~~~~~~~~~~~~~~~~~~~~ INSTANCE ~~~~~~~~~~~~~~~~~~~~~~~~~
78
42
  attr_reader :key
@@ -87,31 +51,32 @@ class Cardname < String
87
51
  freeze
88
52
  end
89
53
 
54
+ # simple string version of name
55
+ # @return [String]
90
56
  def s
91
57
  String.new self
92
58
  end
93
59
  alias_method :to_s, :s
94
60
  alias_method :to_str, :s
95
- # alias_method :dup, :clone
96
61
 
62
+ # @return [Cardname]
97
63
  def to_name
98
64
  self
99
65
  end
100
66
 
101
- def []= index, val
102
- p = parts
103
- p[index] = val
104
- replace self.class.new(p)
105
- end
106
-
107
- def << val
108
- replace self.class.new(parts << val)
67
+ # @return [Symbol]
68
+ def to_sym
69
+ s.to_sym
109
70
  end
110
71
 
72
+ # the key defines the namespace
73
+ # @return [String]
111
74
  def key
112
75
  @key ||= generate_key.freeze
113
76
  end
114
77
 
78
+ # test for same key
79
+ # @return [Boolean]
115
80
  def == other
116
81
  key ==
117
82
  case
@@ -121,6 +86,18 @@ class Cardname < String
121
86
  end
122
87
  end
123
88
 
89
+ # cardname based on part index
90
+ # @return [Cardname]
91
+ def [] *args
92
+ self.class.new part_names[*args]
93
+ end
94
+
95
+ # @see #parts
96
+ # @return [Integer]
97
+ def num_parts
98
+ parts.length
99
+ end
100
+
124
101
  private
125
102
 
126
103
  def generate_key
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cardname
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.15.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan McCutchen
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-01-04 00:00:00.000000000 Z
13
+ date: 2023-03-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -50,6 +50,7 @@ files:
50
50
  - README.md
51
51
  - Rakefile
52
52
  - lib/cardname.rb
53
+ - lib/cardname/class_methods.rb
53
54
  - lib/cardname/contextual.rb
54
55
  - lib/cardname/fields.rb
55
56
  - lib/cardname/manipulate.rb