fat_core 2.0.1 → 3.0.0

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.
@@ -1,284 +1,289 @@
1
1
  require 'damerau-levenshtein'
2
+ require 'active_support/core_ext/regexp'
2
3
 
3
- class String
4
- # Remove leading and trailing white space and compress internal runs of
5
- # white space to a single space.
6
- def clean
7
- strip.squeeze(' ')
8
- end
4
+ module FatCore
5
+ module String
6
+ # Remove leading and trailing white space and compress internal runs of
7
+ # white space to a single space.
8
+ def clean
9
+ strip.squeeze(' ')
10
+ end
9
11
 
10
- def distance(other, block_size: 1, max_distance: 10)
11
- dl = DamerauLevenshtein
12
- # NOTE: DL 'gives up after' max_distance, so the distance function
13
- # will return max_distance+1 if the distance is bigger than that.
14
- # Here we subtract 1 so the max_distance also becomes the max
15
- # return value.
16
- dl.distance(self, other, block_size, max_distance - 1)
17
- end
12
+ def distance(other, block_size: 1, max_distance: 10)
13
+ dl = DamerauLevenshtein
14
+ # NOTE: DL 'gives up after' max_distance, so the distance function
15
+ # will return max_distance+1 if the distance is bigger than that.
16
+ # Here we subtract 1 so the max_distance also becomes the max
17
+ # return value.
18
+ dl.distance(self, other, block_size, max_distance - 1)
19
+ end
18
20
 
19
- # See if self contains colon- or space-separated words that include
20
- # the colon- or space-separated words of other. Return the matched
21
- # portion of self. Other cannot be a regex embedded in a string.
22
- def fuzzy_match(other)
23
- # Remove periods, commas, and apostrophes
24
- other = other.gsub(/[\*.,']/, '')
25
- target = gsub(/[\*.,']/, '')
26
- matchers = other.split(/[: ]+/)
27
- regexp_string = matchers.map { |m| ".*?#{Regexp.escape(m)}.*?" }.join('[: ]')
28
- regexp_string.sub!(/^\.\*\?/, '')
29
- regexp_string.sub!(/\.\*\?$/, '')
30
- regexp = /#{regexp_string}/i
31
- matched_text =
32
- if (match = regexp.match(target))
33
- match[0]
21
+ # See if self contains colon- or space-separated words that include
22
+ # the colon- or space-separated words of other. Return the matched
23
+ # portion of self. Other cannot be a regex embedded in a string.
24
+ def fuzzy_match(other)
25
+ # Remove periods, commas, and apostrophes
26
+ other = other.gsub(/[\*.,']/, '')
27
+ target = gsub(/[\*.,']/, '')
28
+ matchers = other.split(/[: ]+/)
29
+ regexp_string = matchers.map { |m| ".*?#{Regexp.escape(m)}.*?" }.join('[: ]')
30
+ regexp_string.sub!(/^\.\*\?/, '')
31
+ regexp_string.sub!(/\.\*\?$/, '')
32
+ regexp = /#{regexp_string}/i
33
+ matched_text =
34
+ if (match = regexp.match(target))
35
+ match[0]
36
+ end
37
+ matched_text
38
+ end
39
+
40
+ # Here are instance methods for the class that includes Matchable
41
+ # This tries to convert the receiver object into a string, then
42
+ # matches against the given matcher, either via regex or a fuzzy
43
+ # string matcher.
44
+ def matches_with(str)
45
+ if str.nil?
46
+ nil
47
+ elsif str =~ %r{^\s*/}
48
+ re = str.to_regexp
49
+ $& if to_s =~ re
50
+ else
51
+ to_s.fuzzy_match(str)
34
52
  end
35
- matched_text
36
- end
53
+ end
37
54
 
38
- # Here are instance methods for the class that includes Matchable
39
- # This tries to convert the receiver object into a string, then
40
- # matches against the given matcher, either via regex or a fuzzy
41
- # string matcher.
42
- def matches_with(str)
43
- if str.nil?
44
- nil
45
- elsif str =~ %r{^\s*/}
46
- re = str.to_regexp
47
- $& if to_s =~ re
48
- else
49
- to_s.fuzzy_match(str)
55
+ def blank?
56
+ !!self =~ /\A\s*\z/
50
57
  end
51
- end
52
58
 
53
- # Convert a string of the form '/.../Iixm' to a regular expression. However,
54
- # make the regular expression case-insensitive by default and extend the
55
- # modifier syntax to allow '/I' to indicate case-sensitive.
56
- def to_regexp
57
- if self =~ %r{^\s*/([^/]*)/([Iixm]*)\s*$}
58
- body = $1
59
- opts = $2
60
- flags = Regexp::IGNORECASE
61
- unless opts.blank?
62
- flags = 0 if opts.include?('I')
63
- flags |= Regexp::IGNORECASE if opts.include?('i')
64
- flags |= Regexp::EXTENDED if opts.include?('x')
65
- flags |= Regexp::MULTILINE if opts.include?('m')
59
+ # Convert a string of the form '/.../Iixm' to a regular expression. However,
60
+ # make the regular expression case-insensitive by default and extend the
61
+ # modifier syntax to allow '/I' to indicate case-sensitive.
62
+ def to_regexp
63
+ if self =~ %r{^\s*/([^/]*)/([Iixm]*)\s*$}
64
+ body = $1
65
+ opts = $2
66
+ flags = Regexp::IGNORECASE
67
+ unless opts.blank?
68
+ flags = 0 if opts.include?('I')
69
+ flags |= Regexp::IGNORECASE if opts.include?('i')
70
+ flags |= Regexp::EXTENDED if opts.include?('x')
71
+ flags |= Regexp::MULTILINE if opts.include?('m')
72
+ end
73
+ flags = nil if flags.zero?
74
+ Regexp.new(body, flags)
75
+ else
76
+ Regexp.new(self)
66
77
  end
67
- flags = nil if flags.zero?
68
- Regexp.new(body, flags)
69
- else
70
- Regexp.new(self)
71
78
  end
72
- end
73
-
74
- # Convert to symbol "Hello World" -> :hello_world
75
- def as_sym
76
- strip.squeeze(' ').gsub(/\s+/, '_')
77
- .gsub(/[^_A-Za-z0-9]/, '').downcase.to_sym
78
- end
79
79
 
80
- def as_string
81
- self
82
- end
80
+ # Convert to symbol "Hello World" -> :hello_world
81
+ def as_sym
82
+ strip.squeeze(' ').gsub(/\s+/, '_')
83
+ .gsub(/[^_A-Za-z0-9]/, '').downcase.to_sym
84
+ end
83
85
 
84
- def number?
85
- Float(self)
86
- true
87
- rescue ArgumentError
88
- return false
89
- end
86
+ def as_string
87
+ self
88
+ end
90
89
 
91
- # If the string is a number, add grouping commas to the whole number part.
92
- def commify
93
- # Break the number into parts
94
- return self unless clean =~ /\A(-)?(\d*)((\.)?(\d*))?\z/
95
- neg = $1 || ''
96
- whole = $2
97
- frac = $5
98
- # Place the commas in the whole part only
99
- whole = whole.reverse
100
- whole.gsub!(/([0-9]{3})/, '\\1,')
101
- whole.gsub!(/,$/, '')
102
- whole.reverse!
103
- # Reassemble
104
- if frac.blank?
105
- neg + whole
106
- else
107
- neg + whole + '.' + frac
90
+ def number?
91
+ Float(self)
92
+ true
93
+ rescue ArgumentError
94
+ return false
108
95
  end
109
- end
110
96
 
111
- def wrap(width = 70, hang = 0)
112
- result = ''
113
- first_line = true
114
- first_word_on_line = true
115
- line_width_so_far = 0
116
- words = split(' ')
117
- words.each do |w|
118
- if !first_line && first_word_on_line
119
- w = ' ' * hang + w
120
- end
121
- unless first_word_on_line
122
- w = ' ' + w
123
- end
124
- result << w
125
- first_word_on_line = false
126
- line_width_so_far += 1 + w.length
127
- if line_width_so_far >= width
128
- result << "\n"
129
- line_width_so_far = 0
130
- first_line = false
131
- first_word_on_line = true
97
+ # If the string is a number, add grouping commas to the whole number part.
98
+ def commify
99
+ # Break the number into parts
100
+ return self unless clean =~ /\A(-)?(\d*)((\.)?(\d*))?\z/
101
+ neg = $1 || ''
102
+ whole = $2
103
+ frac = $5
104
+ # Place the commas in the whole part only
105
+ whole = whole.reverse
106
+ whole.gsub!(/([0-9]{3})/, '\\1,')
107
+ whole.gsub!(/,$/, '')
108
+ whole.reverse!
109
+ # Reassemble
110
+ if frac.blank?
111
+ neg + whole
112
+ else
113
+ neg + whole + '.' + frac
132
114
  end
133
115
  end
134
- result.strip
135
- end
136
116
 
137
- def tex_quote
138
- r = dup
139
- r = r.gsub(/[{]/, 'XzXzXobXzXzX')
140
- r = r.gsub(/[}]/, 'XzXzXcbXzXzX')
141
- r = r.gsub(/\\/, '\textbackslash{}')
142
- r = r.gsub(/\^/, '\textasciicircum{}')
143
- r = r.gsub(/~/, '\textasciitilde{}')
144
- r = r.gsub(/\|/, '\textbar{}')
145
- r = r.gsub(/\</, '\textless{}')
146
- r = r.gsub(/\>/, '\textgreater{}')
147
- r = r.gsub(/([_$&%#])/) { |m| '\\' + m }
148
- r = r.gsub('XzXzXobXzXzX', '\\{')
149
- r.gsub('XzXzXcbXzXzX', '\\}')
150
- end
117
+ def wrap(width = 70, hang = 0)
118
+ result = ''
119
+ first_line = true
120
+ first_word_on_line = true
121
+ line_width_so_far = 0
122
+ words = split(' ')
123
+ words.each do |w|
124
+ if !first_line && first_word_on_line
125
+ w = ' ' * hang + w
126
+ end
127
+ unless first_word_on_line
128
+ w = ' ' + w
129
+ end
130
+ result << w
131
+ first_word_on_line = false
132
+ line_width_so_far += 1 + w.length
133
+ if line_width_so_far >= width
134
+ result << "\n"
135
+ line_width_so_far = 0
136
+ first_line = false
137
+ first_word_on_line = true
138
+ end
139
+ end
140
+ result.strip
141
+ end
151
142
 
152
- def self.random(size = 8)
153
- ('a'..'z').cycle.take(size).shuffle.join
154
- end
143
+ def tex_quote
144
+ r = dup
145
+ r = r.gsub(/[{]/, 'XzXzXobXzXzX')
146
+ r = r.gsub(/[}]/, 'XzXzXcbXzXzX')
147
+ r = r.gsub(/\\/, '\textbackslash{}')
148
+ r = r.gsub(/\^/, '\textasciicircum{}')
149
+ r = r.gsub(/~/, '\textasciitilde{}')
150
+ r = r.gsub(/\|/, '\textbar{}')
151
+ r = r.gsub(/\</, '\textless{}')
152
+ r = r.gsub(/\>/, '\textgreater{}')
153
+ r = r.gsub(/([_$&%#])/) { |m| '\\' + m }
154
+ r = r.gsub('XzXzXobXzXzX', '\\{')
155
+ r.gsub('XzXzXcbXzXzX', '\\}')
156
+ end
155
157
 
156
- # Convert a string with an all-digit date to an iso string
157
- # E.g., "20090923" -> "2009-09-23"
158
- def digdate2iso
159
- sub(/(\d\d\d\d)(\d\d)(\d\d)/, '\1-\2-\3')
160
- end
158
+ # Convert a string with an all-digit date to an iso string
159
+ # E.g., "20090923" -> "2009-09-23"
160
+ def digdate2iso
161
+ sub(/(\d\d\d\d)(\d\d)(\d\d)/, '\1-\2-\3')
162
+ end
161
163
 
162
- def entitle!
163
- little_words = %w(a an the and or in on under of from as by to)
164
- newwords = []
165
- words = split(/\s+/)
166
- first_word = true
167
- num_words = words.length
168
- words.each_with_index do |w, k|
169
- last_word = (k + 1 == num_words)
170
- if w =~ %r{c/o}i
171
- # Care of
172
- newwords.push('c/o')
173
- elsif w =~ /^p\.?o\.?$/i
174
- # Post office
175
- newwords.push('P.O.')
176
- elsif w =~ /^[0-9]+(st|nd|rd|th)$/i
177
- # Ordinals
178
- newwords.push(w.downcase)
179
- elsif w =~ /^(cr|dr|st|rd|ave|pk|cir)$/i
180
- # Common abbrs to capitalize
181
- newwords.push(w.capitalize)
182
- elsif w =~ /^(us|ne|se|rr)$/i
183
- # Common 2-letter abbrs to upcase
184
- newwords.push(w.upcase)
185
- elsif w =~ /^[0-9].*$/i
186
- # Other runs starting with numbers,
187
- # like 3-A
188
- newwords.push(w.upcase)
189
- elsif w =~ /^(N|S|E|W|NE|NW|SE|SW)$/i
190
- # Compass directions all caps
191
- newwords.push(w.upcase)
192
- elsif w =~ /^[^aeiouy]*$/i && w.size > 2
193
- # All consonants and at least 3 chars, probably abbr
194
- newwords.push(w.upcase)
195
- elsif w =~ /^(\w+)-(\w+)$/i
196
- # Hyphenated double word
197
- newwords.push($1.capitalize + '-' + $2.capitalize)
198
- elsif little_words.include?(w.downcase)
199
- # Only capitalize at beginning or end
200
- newwords.push(first_word || last_word ? w.capitalize : w.downcase)
201
- else
202
- # All else
203
- newwords.push(w.capitalize)
164
+ def entitle!
165
+ little_words = %w(a an the and or in on under of from as by to)
166
+ newwords = []
167
+ words = split(/\s+/)
168
+ first_word = true
169
+ num_words = words.length
170
+ words.each_with_index do |w, k|
171
+ last_word = (k + 1 == num_words)
172
+ if w =~ %r{c/o}i
173
+ # Care of
174
+ newwords.push('c/o')
175
+ elsif w =~ /^p\.?o\.?$/i
176
+ # Post office
177
+ newwords.push('P.O.')
178
+ elsif w =~ /^[0-9]+(st|nd|rd|th)$/i
179
+ # Ordinals
180
+ newwords.push(w.downcase)
181
+ elsif w =~ /^(cr|dr|st|rd|ave|pk|cir)$/i
182
+ # Common abbrs to capitalize
183
+ newwords.push(w.capitalize)
184
+ elsif w =~ /^(us|ne|se|rr)$/i
185
+ # Common 2-letter abbrs to upcase
186
+ newwords.push(w.upcase)
187
+ elsif w =~ /^[0-9].*$/i
188
+ # Other runs starting with numbers,
189
+ # like 3-A
190
+ newwords.push(w.upcase)
191
+ elsif w =~ /^(N|S|E|W|NE|NW|SE|SW)$/i
192
+ # Compass directions all caps
193
+ newwords.push(w.upcase)
194
+ elsif w =~ /^[^aeiouy]*$/i && w.size > 2
195
+ # All consonants and at least 3 chars, probably abbr
196
+ newwords.push(w.upcase)
197
+ elsif w =~ /^(\w+)-(\w+)$/i
198
+ # Hyphenated double word
199
+ newwords.push($1.capitalize + '-' + $2.capitalize)
200
+ elsif little_words.include?(w.downcase)
201
+ # Only capitalize at beginning or end
202
+ newwords.push(first_word || last_word ? w.capitalize : w.downcase)
203
+ else
204
+ # All else
205
+ newwords.push(w.capitalize)
206
+ end
207
+ first_word = false
204
208
  end
205
- first_word = false
209
+ self[0..-1] = newwords.join(' ')
206
210
  end
207
- self[0..-1] = newwords.join(' ')
208
- end
209
211
 
210
- def entitle
211
- dup.entitle!
212
- end
212
+ def entitle
213
+ dup.entitle!
214
+ end
213
215
 
214
- # Format the string according to the given sprintf format.
215
- def format_by(fmt)
216
- return self unless fmt
217
- begin
218
- format fmt, self
219
- rescue ArgumentError
220
- return self
216
+ # Thanks to Eugene at stackoverflow for the following.
217
+ # http://stackoverflow.com/questions/8806643/
218
+ # colorized-output-breaks-linewrapping-with-readline
219
+ # These color strings without confusing readline about the length of
220
+ # the prompt string in the shell. (Unlike the rainbow routines)
221
+ def console_red
222
+ colorize(self, "\001\e[1m\e[31m\002")
221
223
  end
222
- end
223
224
 
224
- # Thanks to Eugene at stackoverflow for the following.
225
- # http://stackoverflow.com/questions/8806643/
226
- # colorized-output-breaks-linewrapping-with-readline
227
- # These color strings without confusing readline about the length of
228
- # the prompt string in the shell. (Unlike the rainbow routines)
229
- def console_red
230
- colorize(self, "\001\e[1m\e[31m\002")
231
- end
225
+ def console_dark_red
226
+ colorize(self, "\001\e[31m\002")
227
+ end
232
228
 
233
- def console_dark_red
234
- colorize(self, "\001\e[31m\002")
235
- end
229
+ def console_green
230
+ colorize(self, "\001\e[1m\e[32m\002")
231
+ end
236
232
 
237
- def console_green
238
- colorize(self, "\001\e[1m\e[32m\002")
239
- end
233
+ def console_dark_green
234
+ colorize(self, "\001\e[32m\002")
235
+ end
240
236
 
241
- def console_dark_green
242
- colorize(self, "\001\e[32m\002")
243
- end
237
+ def console_yellow
238
+ colorize(self, "\001\e[1m\e[33m\002")
239
+ end
244
240
 
245
- def console_yellow
246
- colorize(self, "\001\e[1m\e[33m\002")
247
- end
241
+ def console_dark_yellow
242
+ colorize(self, "\001\e[33m\002")
243
+ end
248
244
 
249
- def console_dark_yellow
250
- colorize(self, "\001\e[33m\002")
251
- end
245
+ def console_blue
246
+ colorize(self, "\001\e[1m\e[34m\002")
247
+ end
252
248
 
253
- def console_blue
254
- colorize(self, "\001\e[1m\e[34m\002")
255
- end
249
+ def console_dark_blue
250
+ colorize(self, "\001\e[34m\002")
251
+ end
256
252
 
257
- def console_dark_blue
258
- colorize(self, "\001\e[34m\002")
259
- end
253
+ def console_purple
254
+ colorize(self, "\001\e[1m\e[35m\002")
255
+ end
260
256
 
261
- def console_purple
262
- colorize(self, "\001\e[1m\e[35m\002")
263
- end
257
+ def console_cyan
258
+ colorize(self, "\001\e[1m\e[36m\002")
259
+ end
264
260
 
265
- def console_cyan
266
- colorize(self, "\001\e[1m\e[36m\002")
267
- end
261
+ def console_def
262
+ colorize(self, "\001\e[1m\002")
263
+ end
268
264
 
269
- def console_def
270
- colorize(self, "\001\e[1m\002")
271
- end
265
+ def console_bold
266
+ colorize(self, "\001\e[1m\002")
267
+ end
272
268
 
273
- def console_bold
274
- colorize(self, "\001\e[1m\002")
275
- end
269
+ def console_blink
270
+ colorize(self, "\001\e[5m\002")
271
+ end
276
272
 
277
- def console_blink
278
- colorize(self, "\001\e[5m\002")
279
- end
273
+ def colorize(text, color_code)
274
+ "#{color_code}#{text}\001\e[0m\002"
275
+ end
276
+
277
+ module ClassMethods
278
+ def random(size = 8)
279
+ ('a'..'z').cycle.take(size).shuffle.join
280
+ end
281
+ end
280
282
 
281
- def colorize(text, color_code)
282
- "#{color_code}#{text}\001\e[0m\002"
283
+ def self.included(base)
284
+ base.extend(ClassMethods)
285
+ end
283
286
  end
284
287
  end
288
+
289
+ String.include FatCore::String
@@ -1,15 +1,21 @@
1
- class Symbol
2
- # Convert to capitalized string: :hello_world -> "Hello World"
3
- def entitle
4
- to_s.tr('_', ' ').split(' ').join(' ').entitle
5
- end
6
- alias as_string entitle
1
+ require 'fat_core/string'
7
2
 
8
- def as_sym
9
- self
10
- end
3
+ module FatCore
4
+ module Symbol
5
+ # Convert to capitalized string: :hello_world -> "Hello World"
6
+ def entitle
7
+ to_s.tr('_', ' ').split(' ').join(' ').entitle
8
+ end
9
+ alias as_string entitle
11
10
 
12
- def tex_quote
13
- to_s.tex_quote
11
+ def as_sym
12
+ self
13
+ end
14
+
15
+ def tex_quote
16
+ to_s.tex_quote
17
+ end
14
18
  end
15
19
  end
20
+
21
+ Symbol.include(FatCore::Symbol)
@@ -1,7 +1,7 @@
1
1
  module FatCore
2
- MAJOR = 2
2
+ MAJOR = 3
3
3
  MINOR = 0
4
- PATCH = 1
4
+ PATCH = 0
5
5
 
6
6
  VERSION = [MAJOR, MINOR, PATCH].compact.join('.')
7
7
  end
data/lib/fat_core.rb CHANGED
@@ -1,22 +1 @@
1
-
2
- require 'date'
3
- require 'active_support'
4
- require 'active_support/core_ext'
5
- require 'active_support/number_helper'
6
- require 'csv'
7
-
8
1
  require 'fat_core/version'
9
-
10
- require 'fat_core/array'
11
- require 'fat_core/date'
12
- require 'fat_core/boolean'
13
- require 'fat_core/enumerable'
14
- require 'fat_core/hash'
15
- require 'fat_core/kernel'
16
- require 'fat_core/latex_eruby'
17
- require 'fat_core/nil'
18
- require 'fat_core/numeric'
19
- require 'fat_core/period'
20
- require 'fat_core/range'
21
- require 'fat_core/string'
22
- require 'fat_core/symbol'
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'fat_core/array'
4
+
3
5
  describe Array do
4
6
  it 'should be able to report its last index' do
5
7
  letters = ('a'..'z').to_a
@@ -0,0 +1,7 @@
1
+ require 'fat_core/big_decimal'
2
+
3
+ describe BigDecimal do
4
+ it 'should provide a human-readable inspect for BigDecimal' do
5
+ expect(BigDecimal.new('33.45').inspect).to eq '33.45'
6
+ end
7
+ end