Moved #enumerate onto StringRay. Now String#enumerate (StringRay::Includes#enumerate...
[stringray.git] / lib / stringray.rb
blobc733602e1ce1f49c1a6cbc582890449fd8f31085
1 require 'stringray/core_ext'
2 require 'stringray/includes'
4 class StringRay < Array
5   Version = 3
6   
7   @@whitespace = nil
8   @@delemiters = nil
9   
10   ##
11   # @see StringRay::Includes#enumerate
12   # @see StringRay::Includes.whitespace=
13   # Controls how +StringRay::Includes#enumerate+ deals with whitespace by default.
14   # 
15   # @param [Symbol] whitespace How to handle whitespace - :attach_before,
16   #   :standalone, or :attach_after
17   def self.whitespace= whitespace
18     @@whitespace = whitespace
19   end
20   
21   def self.whitespace
22     @@whitespace ||= :attach_before
23   end
25   ##
26   # @see StringRay::Includes#enumerate
27   # @see StringRay::Includes.delemiters=
28   # Controls how +StringRay::Includes#enumerate+ deals with delemiters by default.
29   # 
30   # @param [Symbol] delemiters How to handle delemiters - :attach_before,
31   #   :standalone, or :attach_after
32   def self.delemiters= delemiters
33     @@delemiters = delemiters
34   end
35   
36   def self.delemiters
37     @@delemiters ||= :attach_before
38   end
39   
40   # @see StringRay::Word.new
41   def self.Word word; Word.new word; end
42   
43   ##
44   # @see StringRay::Includes#to_stray
45   # @see #whitespace
46   # @see #delemiters
47   # Enumerates a string, returning an array plain +String+s.
48   # 
49   # @param [Hash] options A hash of options
50   # @yield [word] Allows each word in the string to be operated on after it is
51   #   processed
52   # @yieldparam [String] word The last processed word
53   # @return [Array[String]] An array of words
54   # @since 1
55   def enumerate options = {}, &block
56     # TODO: Can we clean this up, into a simple #inject call? I bet so.
57     # TODO: This really should return an Enumerator object. Seriously.
58     mapped = []
59     attach_before_next = []
60     
61     self.each do |element|
62       case element
63       when Delimiter
64         case options[:delemiters] || StringRay::delemiters
65         when :standalone
66           mapped << [element]
67         when :attach_after
68           attach_before_next << element
69         else
70           if attach_before_next.empty?
71             if mapped.last
72               mapped.last << element
73             else
74               attach_before_next << element
75             end
76           else
77             attach_before_next << element
78           end
79         end
80         
81       when Whitespace
82         case options[:whitespace] || StringRay::whitespace
83         when :standalone
84           mapped << [element]
85         when :attach_after
86           attach_before_next << element
87         else
88           if attach_before_next.empty?
89             if mapped.last
90               mapped.last << element
91             else
92               attach_before_next << element
93             end
94           else
95             attach_before_next << element
96           end
97         end
98         
99       when Word
100         if not attach_before_next.empty?
101           mapped << [attach_before_next, element].flatten
102           attach_before_next = []
103         else
104           mapped << [element]
105         end
106         
107       end
108     end
109     
110     if not attach_before_next.empty?
111       mapped << [Word.new] unless mapped.last
112       (mapped.last << attach_before_next).flatten!
113     end
114     
115     mapped.map do |arr|
116       string = arr.map{|w|w.to_s}.join
117       yield string if block_given?
118       string
119     end
120   end
121   
122   ##
123   # A wrapper class for strings that are 'words' in and of themselves,
124   # composed of 'word characters'.
125   class Word < String
126     def inspect
127       "(#{self})"
128     end
129   end
130   
131   # @see StringRay::Whitespace.new
132   def self.Whitespace whitespace; Whitespace.new whitespace; end
133   
134   ##
135   # A wrapper class for strings that are 'whitespace' composed of 'whitespace
136   # characters'.
137   class Whitespace < String
138     Characters = [" ", "\t", "\n"]
139     
140     def inspect
141       "#{self}"
142     end
143   end
144   
145   # @see StringRay::Delimiter.new
146   def self.Delimiter delimiter; Delimiter.new delimiter; end
147   
148   ##
149   # A wrapper class for strings that are 'delimiters' composed of 'delimiter
150   # characters'.
151   class Delimiter < String
152     Characters = ['-', ',', '.', '?', '!', ':', ';', '/', '\\', '|']
153     
154     def inspect
155       "<#{self}>"
156     end
157   end
158   
159   def inspect
160     "\"#{self.map(&:inspect).join ''}\""
161   end
162