1 require 'stringray/core_ext'
11 # Controls how +#enumerate+ deals with whitespace.
13 # @param [Symbol] whitespace How to handle whitespace - :attach_before,
14 # :standalone, or :attach_after
15 def self.whitespace= whitespace
16 @@whitespace = whitespace
20 @@whitespace ||= :attach_before
25 # Controls how +#enumerate+ deals with delemiters.
27 # @param [Symbol] delemiters How to handle delemiters - :attach_before,
28 # :standalone, or :attach_after
29 def self.delemiters= delemiters
30 @@delemiters = delemiters
34 @@delemiters ||= :attach_before
38 # Splits a string into an array of +StringRay+ container objects (+Word+,
39 # +Whitespace+, and +Delimiter+).
41 # @yield [element] Allows each 'element' of the string to be operated on
42 # after it is processed
43 # @yieldparam [Word, Whitespace, Delimiter] element The last processed
45 # @return [Array[Word, Whitespace, Delimiter]] An array of +StringRay+
50 new_element = lambda do |element|
51 yield ray.last if block_given? unless ray.empty?
55 self.scan(/./um) do |char|
56 if Delimiter::Characters.include? char
57 new_element[Delimiter.new(char)]
59 elsif Whitespace::Characters.include? char
60 if ray.last.is_a? Whitespace
63 new_element[Whitespace.new(char)]
67 if ray.last.is_a? Word
70 new_element[Word.new(char)]
88 # Enumerates a string, similar to +#to_stray+, but returning an array of
89 # plain +String+s instead of container objects.
91 # @param [Hash] options A hash of options
92 # @yield [word] Allows each word in the string to be operated on after it is
94 # @yieldparam [String] word The last processed word
95 # @return [Array[String]] An array of words
97 def enumerate options = {}, &block
99 attach_before_next = []
101 self.to_stray do |element|
104 case options[:delemiters] || StringRay::delemiters
108 attach_before_next << element
110 if attach_before_next.empty?
112 mapped.last << element
114 attach_before_next << element
117 attach_before_next << element
122 case options[:whitespace] || StringRay::whitespace
126 attach_before_next << element
128 if attach_before_next.empty?
130 mapped.last << element
132 attach_before_next << element
135 attach_before_next << element
140 if not attach_before_next.empty?
141 mapped << [attach_before_next, element].flatten
142 attach_before_next = []
150 if not attach_before_next.empty?
151 mapped << [Word.new] unless mapped.last
152 (mapped.last << attach_before_next).flatten!
156 string = arr.map{|w|w.to_s}.join
157 yield string if block_given?
163 alias_method :each_word, :enumerate
165 # @see StringRay::Word.new
166 def Word word; Word.new word; end
169 # A wrapper class for strings that are 'words' in and of themselves,
170 # composed of 'word characters'.
177 # @see StringRay::Whitespace.new
178 def Whitespace whitespace; Whitespace.new whitespace; end
181 # A wrapper class for strings that are 'whitespace' composed of 'whitespace
183 class Whitespace < String
184 Characters = [" ", "\t", "\n"]
191 # @see StringRay::Delimiter.new
192 def Delimiter delimiter; Delimiter.new delimiter; end
195 # A wrapper class for strings that are 'delimiters' composed of 'delimiter
197 class Delimiter < String
198 Characters = ['-', ',', '.', '?', '!', ':', ';', '/', '\\', '|']
205 # This is mixed into any class including +StringRay+. It exposes
206 # +::make_enumerable!+ to said class.
210 # This overrides +String#each+ with +StringRay#enumerate+, thus allowing
211 # us to include +Enumerable+. Be careful, this breaks lots of existing
212 # code which depends on the old methodology of +String#each+! The
213 # overridden +String#each+ functionality will be exposed as
217 if RUBY_VERSION <= "1.9"
218 Kernel::warn "overriding String#each with StringRay#enumerate; this may break old libaries!"
219 alias_method :each_at, :each
221 alias_method :each, :enumerate
229 def self.included klass
230 klass.send :extend, Extendables