Class: MakeTaggable::TagList
- Inherits:
-
Array
- Object
- Array
- MakeTaggable::TagList
- Defined in:
- lib/make_taggable/tag_list.rb
Overview
The list of tag names held against one context of one record.
A tag list is an Array, so everything Array offers works on it. What it adds is parsing, and cleaning: blank entries are dropped, entries are converted to strings and stripped, and duplicates are removed according to the configured case sensitivity.
Instance Attribute Summary collapse
-
#owner ⇒ ActiveRecord::Base, NilClass
The tagger whose tags these are, when the list belongs to an owner.
-
#parser ⇒ Class
The parser this list uses when asked to parse.
Instance Method Summary collapse
-
#+(other) ⇒ MakeTaggable::TagList
Joins two tag lists into a third, leaving both untouched.
-
#<<(obj) ⇒ MakeTaggable::TagList
Adds one tag to the list.
-
#add(*names) ⇒ MakeTaggable::TagList
Adds tags to the list, ignoring duplicates and blanks.
-
#concat(other_tag_list) ⇒ MakeTaggable::TagList
Appends another list's tags to this one.
-
#initialize(*args) ⇒ MakeTaggable::TagList
constructor
Builds a tag list from the given names.
-
#remove(*names) ⇒ MakeTaggable::TagList
Removes tags from the list.
-
#to_s ⇒ String
Renders the list as a delimited string, suitable for a form field.
Constructor Details
#initialize(*args) ⇒ MakeTaggable::TagList
Builds a tag list from the given names.
36 37 38 |
# File 'lib/make_taggable/tag_list.rb', line 36 def initialize(*args) add(*args) end |
Instance Attribute Details
#owner ⇒ ActiveRecord::Base, NilClass
The tagger whose tags these are, when the list belongs to an owner.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/make_taggable/tag_list.rb', line 25 class TagList < Array attr_accessor :owner attr_writer :parser ## # Builds a tag list from the given names. # # @param args [Array<String, Symbol>] the tag names, optionally followed by an options hash # accepted by {#add} # @return [MakeTaggable::TagList] # def initialize(*args) add(*args) end ## # The parser this list uses when asked to parse. # # Falls back to the configured {MakeTaggable.default_parser}, and deliberately does not store # it. A stored parser is a Class held in an instance variable, and Psych validates instance # variables when dumping, so carrying one made every tag list unserialisable -- `audited`, # Active Job arguments and `serialize` columns all refuse it. # # A parser assigned explicitly is still stored, and a list carrying one is subject to the same # limitation. # # @return [Class] # def parser @parser || MakeTaggable.default_parser end ## # Adds tags to the list, ignoring duplicates and blanks. # # @param names [Array<String, Symbol>] the tags to add, optionally followed by an options hash # @option names [TrueClass, FalseClass] :parse whether to parse the input as a delimited string # @option names [Class] :parser a parser to use for this call only # @return [MakeTaggable::TagList] self, so calls can be chained # # @example # tag_list.add("Fun", "Happy") # tag_list.add("Fun, Happy", parse: true) # def add(*names) (names) concat(names) clean! self end ## # Adds one tag to the list. # # @param obj [String, Symbol] the tag to add # @return [MakeTaggable::TagList] self, so appends can be chained # def <<(obj) add(obj) end ## # Joins two tag lists into a third, leaving both untouched. # # @param other [Array<String>] the tags to append # @return [MakeTaggable::TagList] a new list # def +(other) TagList.new.add(self).add(other) end ## # Appends another list's tags to this one. # # @param other_tag_list [Array<String>] the tags to append # @return [MakeTaggable::TagList] self # def concat(other_tag_list) super.send(:clean!) self end ## # Removes tags from the list. # # @param names [Array<String, Symbol>] the tags to remove, optionally followed by an options # hash accepted by {#add} # @return [MakeTaggable::TagList] self # # @example # tag_list.remove("Sad", "Lonely") # tag_list.remove("Sad, Lonely", parse: true) # def remove(*names) (names) # The list holds strings, so compare strings. Everything else that takes # tag names normalises them -- add runs them through clean!, tagged_with # parses them -- and a symbol silently matching nothing here was the odd # one out. names = names.map(&:to_s) delete_if { |name| names.include?(name) } self end ## # Renders the list as a delimited string, suitable for a form field. # # Tags containing the delimiter are quoted, so the string parses back into the same list. # # @return [String] # # @example # MakeTaggable::TagList.new("Round", "Square,Cube").to_s # # => 'Round, "Square,Cube"' # def to_s = frozen? ? dup : self .send(:clean!) delimiter = Regexp.union(Array(MakeTaggable.delimiter)) .map { |name| name.index(delimiter) ? "\"#{name}\"" : name }.join(MakeTaggable.glue) end private # Convert everything to string, remove whitespace, duplicates, and blanks. def clean! reject!(&:blank?) map!(&:to_s) map!(&:strip) map!(&:downcase) if MakeTaggable.force_lowercase # A name with no ASCII in it parameterizes to "", and reject! below would # then drop it -- so the tag vanished rather than being slugged. Keep the # original where there is no slug to be had; a caller who wanted strict # slugs still gets one wherever one exists. map! { |tag| tag.parameterize.presence || tag } if MakeTaggable.force_parameterize MakeTaggable.strict_case_match ? uniq! : uniq! { |tag| tag.downcase } self end def (args) = args.last.is_a?(Hash) ? args.pop : {} .assert_valid_keys :parse, :parser chosen_parser = [:parser] || parser args.map! { |a| chosen_parser.new(a).parse } if [:parse] || [:parser] args.flatten! end end |
#parser ⇒ Class
The parser this list uses when asked to parse.
Falls back to the configured MakeTaggable.default_parser, and deliberately does not store
it. A stored parser is a Class held in an instance variable, and Psych validates instance
variables when dumping, so carrying one made every tag list unserialisable -- audited,
Active Job arguments and serialize columns all refuse it.
A parser assigned explicitly is still stored, and a list carrying one is subject to the same limitation.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/make_taggable/tag_list.rb', line 25 class TagList < Array attr_accessor :owner attr_writer :parser ## # Builds a tag list from the given names. # # @param args [Array<String, Symbol>] the tag names, optionally followed by an options hash # accepted by {#add} # @return [MakeTaggable::TagList] # def initialize(*args) add(*args) end ## # The parser this list uses when asked to parse. # # Falls back to the configured {MakeTaggable.default_parser}, and deliberately does not store # it. A stored parser is a Class held in an instance variable, and Psych validates instance # variables when dumping, so carrying one made every tag list unserialisable -- `audited`, # Active Job arguments and `serialize` columns all refuse it. # # A parser assigned explicitly is still stored, and a list carrying one is subject to the same # limitation. # # @return [Class] # def parser @parser || MakeTaggable.default_parser end ## # Adds tags to the list, ignoring duplicates and blanks. # # @param names [Array<String, Symbol>] the tags to add, optionally followed by an options hash # @option names [TrueClass, FalseClass] :parse whether to parse the input as a delimited string # @option names [Class] :parser a parser to use for this call only # @return [MakeTaggable::TagList] self, so calls can be chained # # @example # tag_list.add("Fun", "Happy") # tag_list.add("Fun, Happy", parse: true) # def add(*names) (names) concat(names) clean! self end ## # Adds one tag to the list. # # @param obj [String, Symbol] the tag to add # @return [MakeTaggable::TagList] self, so appends can be chained # def <<(obj) add(obj) end ## # Joins two tag lists into a third, leaving both untouched. # # @param other [Array<String>] the tags to append # @return [MakeTaggable::TagList] a new list # def +(other) TagList.new.add(self).add(other) end ## # Appends another list's tags to this one. # # @param other_tag_list [Array<String>] the tags to append # @return [MakeTaggable::TagList] self # def concat(other_tag_list) super.send(:clean!) self end ## # Removes tags from the list. # # @param names [Array<String, Symbol>] the tags to remove, optionally followed by an options # hash accepted by {#add} # @return [MakeTaggable::TagList] self # # @example # tag_list.remove("Sad", "Lonely") # tag_list.remove("Sad, Lonely", parse: true) # def remove(*names) (names) # The list holds strings, so compare strings. Everything else that takes # tag names normalises them -- add runs them through clean!, tagged_with # parses them -- and a symbol silently matching nothing here was the odd # one out. names = names.map(&:to_s) delete_if { |name| names.include?(name) } self end ## # Renders the list as a delimited string, suitable for a form field. # # Tags containing the delimiter are quoted, so the string parses back into the same list. # # @return [String] # # @example # MakeTaggable::TagList.new("Round", "Square,Cube").to_s # # => 'Round, "Square,Cube"' # def to_s = frozen? ? dup : self .send(:clean!) delimiter = Regexp.union(Array(MakeTaggable.delimiter)) .map { |name| name.index(delimiter) ? "\"#{name}\"" : name }.join(MakeTaggable.glue) end private # Convert everything to string, remove whitespace, duplicates, and blanks. def clean! reject!(&:blank?) map!(&:to_s) map!(&:strip) map!(&:downcase) if MakeTaggable.force_lowercase # A name with no ASCII in it parameterizes to "", and reject! below would # then drop it -- so the tag vanished rather than being slugged. Keep the # original where there is no slug to be had; a caller who wanted strict # slugs still gets one wherever one exists. map! { |tag| tag.parameterize.presence || tag } if MakeTaggable.force_parameterize MakeTaggable.strict_case_match ? uniq! : uniq! { |tag| tag.downcase } self end def (args) = args.last.is_a?(Hash) ? args.pop : {} .assert_valid_keys :parse, :parser chosen_parser = [:parser] || parser args.map! { |a| chosen_parser.new(a).parse } if [:parse] || [:parser] args.flatten! end end |
Instance Method Details
#+(other) ⇒ MakeTaggable::TagList
Joins two tag lists into a third, leaving both untouched.
92 93 94 |
# File 'lib/make_taggable/tag_list.rb', line 92 def +(other) TagList.new.add(self).add(other) end |
#<<(obj) ⇒ MakeTaggable::TagList
Adds one tag to the list.
82 83 84 |
# File 'lib/make_taggable/tag_list.rb', line 82 def <<(obj) add(obj) end |
#add(*names) ⇒ MakeTaggable::TagList
Adds tags to the list, ignoring duplicates and blanks.
69 70 71 72 73 74 |
# File 'lib/make_taggable/tag_list.rb', line 69 def add(*names) (names) concat(names) clean! self end |
#concat(other_tag_list) ⇒ MakeTaggable::TagList
Appends another list's tags to this one.
102 103 104 105 |
# File 'lib/make_taggable/tag_list.rb', line 102 def concat(other_tag_list) super.send(:clean!) self end |
#remove(*names) ⇒ MakeTaggable::TagList
Removes tags from the list.
118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/make_taggable/tag_list.rb', line 118 def remove(*names) (names) # The list holds strings, so compare strings. Everything else that takes # tag names normalises them -- add runs them through clean!, tagged_with # parses them -- and a symbol silently matching nothing here was the odd # one out. names = names.map(&:to_s) delete_if { |name| names.include?(name) } self end |
#to_s ⇒ String
Renders the list as a delimited string, suitable for a form field.
Tags containing the delimiter are quoted, so the string parses back into the same list.
142 143 144 145 146 147 148 149 150 151 |
# File 'lib/make_taggable/tag_list.rb', line 142 def to_s = frozen? ? dup : self .send(:clean!) delimiter = Regexp.union(Array(MakeTaggable.delimiter)) .map { |name| name.index(delimiter) ? "\"#{name}\"" : name }.join(MakeTaggable.glue) end |