iron-extensions 1.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.
- data/.rspec +1 -0
- data/History.txt +6 -0
- data/LICENSE +20 -0
- data/README.rdoc +101 -0
- data/lib/iron/extensions.rb +5 -0
- data/lib/iron/extensions/array.rb +24 -0
- data/lib/iron/extensions/enumerable.rb +13 -0
- data/lib/iron/extensions/file.rb +24 -0
- data/lib/iron/extensions/fixnum.rb +27 -0
- data/lib/iron/extensions/kernel.rb +15 -0
- data/lib/iron/extensions/math.rb +27 -0
- data/lib/iron/extensions/nil.rb +8 -0
- data/lib/iron/extensions/numeric.rb +35 -0
- data/lib/iron/extensions/object.rb +8 -0
- data/lib/iron/extensions/range.rb +13 -0
- data/lib/iron/extensions/regexp.rb +8 -0
- data/lib/iron/extensions/string.rb +172 -0
- data/lib/iron/extensions/symbol.rb +12 -0
- data/sample.rdoc +3 -0
- data/spec/extensions/enumerable_spec.rb +12 -0
- data/spec/extensions/object_spec.rb +11 -0
- data/spec/extensions/string_spec.rb +82 -0
- data/spec/spec_helper.rb +9 -0
- data/version.txt +1 -0
- metadata +81 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require <%= File.join(File.expand_path(File.dirname(__FILE__)), 'spec', 'spec_helper.rb') %>
|
data/History.txt
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Irongaze Consulting LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
'Software'), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
= GEM: iron-extensions
|
2
|
+
|
3
|
+
Written by Rob Morris @ Irongaze Consulting LLC (http://irongaze.com)
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Helpful extensions to core Ruby classes
|
8
|
+
|
9
|
+
== ADDED EXTENSIONS:
|
10
|
+
|
11
|
+
* Array#rand / Array#rand! - pull n random items from the array
|
12
|
+
|
13
|
+
[1,2,3,4,5].rand(2) # => [2, 5]
|
14
|
+
|
15
|
+
* Array#shuffle / Array#shuffle! - randomly reorder the array
|
16
|
+
|
17
|
+
[1,2,3,4,5].shuffle # => [2,4,1,5,3]
|
18
|
+
|
19
|
+
* Array#list_join - join as a list, ignoring blank/nil entries
|
20
|
+
|
21
|
+
[1, 2, nil, '', 'count'].list_join # => '1, 2, count'
|
22
|
+
|
23
|
+
* Enumerable#to_hash - convert an array or other enumerable to a hash using a block or constant
|
24
|
+
|
25
|
+
[:frog, :pig].to_hash {|n| n.to_s.capitalize} # => {:frog => 'Frog', :pig => 'Pig'}
|
26
|
+
[:frog, :pig].to_hash(nil) # => {:frog => nil, :pig => nil}
|
27
|
+
|
28
|
+
* File.replace - atomic replacement of a file given a block to generate it
|
29
|
+
|
30
|
+
# Defers deleting old file until block completes successfully (ie no exceptions), then
|
31
|
+
# moves the new file into the old file's location
|
32
|
+
File.replace('./config') do |file|
|
33
|
+
file.write("PRODUCTION: true")
|
34
|
+
end
|
35
|
+
|
36
|
+
* Fixnum#blank? - always false
|
37
|
+
* Fixnum#to_human_size - size to MB/GB/whatever, lifted from Rails
|
38
|
+
|
39
|
+
123456.to_human_size # => "120.5 KB"
|
40
|
+
|
41
|
+
* Kernel#capture_stdout - capture all text sent to STDOUT within the passed block
|
42
|
+
|
43
|
+
# Will result in out == 'Hi mom!\n'
|
44
|
+
out = capture_stdout do
|
45
|
+
puts 'Hi mom!'
|
46
|
+
end
|
47
|
+
|
48
|
+
* Math.max/Math.min - find the max/min value passed
|
49
|
+
|
50
|
+
Math.max(2,10) # => 10
|
51
|
+
|
52
|
+
* Math.scale_to_fit - shrink width and height vals to fit in a box, preserving aspect ratio
|
53
|
+
|
54
|
+
Math.scale_to_fit(100, 100, 50, 80) # => 50, 50
|
55
|
+
|
56
|
+
* Nil#blank? - always true
|
57
|
+
|
58
|
+
* Numeric#bound - bound a given number to a range
|
59
|
+
|
60
|
+
4.bound(5,10) # => 4
|
61
|
+
|
62
|
+
* Object#in? - sugar to make expressing inclusion clearer
|
63
|
+
|
64
|
+
1.in? [2,3,4] # => false
|
65
|
+
'foo'.in? ['foo', 'bar'] # => true
|
66
|
+
|
67
|
+
* Range#bound - ensure a number is in a range
|
68
|
+
|
69
|
+
(1..5).bound(6) # => 5
|
70
|
+
|
71
|
+
* Regexp::IP_ADDRESS, Regexp::EMAIL_ADDRESS, Regexp::DOMAIN - commonly useful regexen
|
72
|
+
|
73
|
+
* String#blank? - true if empty?
|
74
|
+
* String#append / String#prepend - this should be in Ruby core
|
75
|
+
* String#to_date - "better" date parser than Date.parse
|
76
|
+
* String#to_dashcase - perfect for permalinks!
|
77
|
+
* String#smart_truncate - truncate honoring word boundaries
|
78
|
+
* String#integer? - true when string represents an integer
|
79
|
+
* String#extract - simplifies pulling info out of strings using regexen
|
80
|
+
|
81
|
+
"Irongaze Consulting".extract(/^[a-z]/i) # => "Irongaze"
|
82
|
+
dollars, cents = "$12.95".extract(/([0-9]+)\.([0-9]+)/) # => dollars == '12' and cents == '95'
|
83
|
+
|
84
|
+
* Symbol#blank? - always false
|
85
|
+
* Symbol#to_dashcase - same as for String
|
86
|
+
|
87
|
+
== SYNOPSIS:
|
88
|
+
|
89
|
+
To use:
|
90
|
+
|
91
|
+
require 'iron/extensions'
|
92
|
+
|
93
|
+
== REQUIREMENTS:
|
94
|
+
|
95
|
+
* None
|
96
|
+
|
97
|
+
== INSTALL:
|
98
|
+
|
99
|
+
To install, simply run:
|
100
|
+
|
101
|
+
sudo gem install iron-extensions
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
class Array
|
3
|
+
unless [].respond_to?(:shuffle)
|
4
|
+
def shuffle
|
5
|
+
sort_by { Kernel.rand }
|
6
|
+
end
|
7
|
+
|
8
|
+
def shuffle!
|
9
|
+
self.replace shuffle
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def rand(count = 1)
|
14
|
+
shuffle[0...count]
|
15
|
+
end
|
16
|
+
|
17
|
+
def rand!(count = 1)
|
18
|
+
self.replace rand(count)
|
19
|
+
end
|
20
|
+
|
21
|
+
def list_join(sep = ', ')
|
22
|
+
self.select{|e| !e.blank?}.join(sep)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Enumerable
|
2
|
+
|
3
|
+
# Converts an enumerable into a hash, by accepting an initial value
|
4
|
+
# or a block to compute the value for a given key.
|
5
|
+
def to_hash(init_val = nil)
|
6
|
+
hash = {}
|
7
|
+
self.each do |key|
|
8
|
+
hash[key] = block_given? ? yield(key) : init_val
|
9
|
+
end
|
10
|
+
hash
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class File
|
4
|
+
|
5
|
+
# Atomic replace code - write to temp file, rename to source file path
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# File.safe_replace('/etc/foo.conf') do |file|
|
9
|
+
# file.write('bob=1234')
|
10
|
+
# end
|
11
|
+
def self.safe_replace(path, perm=nil) # :yields: file
|
12
|
+
begin
|
13
|
+
tmp_path = path + '.tmp' + Kernel.rand(99999).to_s
|
14
|
+
end while File.exist?(tmp_path)
|
15
|
+
|
16
|
+
file = File.open(tmp_path, 'w', perm)
|
17
|
+
yield file
|
18
|
+
file.close
|
19
|
+
|
20
|
+
FileUtils.mv(tmp_path, path)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
class Fixnum
|
3
|
+
# Lifted from Rails' NumberHelper view helper
|
4
|
+
def to_human_size(precision=1)
|
5
|
+
size = Kernel.Float(self)
|
6
|
+
case
|
7
|
+
when size.to_i == 1 then
|
8
|
+
"1 Byte"
|
9
|
+
when size < 1024 then
|
10
|
+
"#{size} Bytes"
|
11
|
+
when size < 1024*1024 then
|
12
|
+
"#{(size / 1024).to_display(precision)} KB"
|
13
|
+
when size < 1024*1024*1024 then
|
14
|
+
"#{(size / (1024*1024)).to_display(precision)} MB"
|
15
|
+
when size < 1024*1024*1024*1024 then
|
16
|
+
"#{(size / (1024*1024*1024)).to_display(precision)} GB"
|
17
|
+
else
|
18
|
+
"#{(size / (1024*1024*1024*1024)).to_display(precision)} GB"
|
19
|
+
end
|
20
|
+
rescue
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def blank?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
module Math
|
3
|
+
def self.min(a,b)
|
4
|
+
a <= b ? a : b
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.max(a,b)
|
8
|
+
a >= b ? a : b
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.scale_to_fit(w,h,max_w,max_h)
|
12
|
+
ratio = max_w.to_f / max_h.to_f
|
13
|
+
nw, nh = w, h
|
14
|
+
cur_ratio = nw.to_f / nh.to_f
|
15
|
+
|
16
|
+
if cur_ratio >= ratio
|
17
|
+
nw = max_w
|
18
|
+
nh = max_w / cur_ratio
|
19
|
+
else
|
20
|
+
nh = max_h
|
21
|
+
nw = max_h * cur_ratio
|
22
|
+
end
|
23
|
+
|
24
|
+
return nw.to_i, nh.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
class Numeric
|
3
|
+
|
4
|
+
# Returns self, bounded to min/max values
|
5
|
+
def bound(min, max)
|
6
|
+
min, max = max, min if max < min
|
7
|
+
return min if min > self
|
8
|
+
return max if max < self
|
9
|
+
self
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_display(decimal_count = nil, include_thousands = true)
|
13
|
+
res = ''
|
14
|
+
decimal = self.to_s.extract(/\.([0-9]+)/)
|
15
|
+
unless decimal.nil? || decimal_count.nil?
|
16
|
+
decimal = decimal[0...decimal_count].ljust(decimal_count,'0')
|
17
|
+
end
|
18
|
+
val = self.to_i.abs
|
19
|
+
if include_thousands
|
20
|
+
while val > 999
|
21
|
+
res.prepend(',' + (val % 1000).to_s.rjust(3,'0'))
|
22
|
+
val /= 1000
|
23
|
+
end
|
24
|
+
end
|
25
|
+
res.prepend(val.to_s) if val > 0 || res.empty?
|
26
|
+
res = '-' + res if self < 0
|
27
|
+
res = res + '.' + decimal unless decimal.blank?
|
28
|
+
res
|
29
|
+
end
|
30
|
+
|
31
|
+
#def to_currency
|
32
|
+
# Currency::parse(self)
|
33
|
+
#end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class String
|
4
|
+
|
5
|
+
# Provide helper for nil/"" blankness checker
|
6
|
+
def blank?
|
7
|
+
empty?
|
8
|
+
end
|
9
|
+
|
10
|
+
def prepend(str)
|
11
|
+
self.insert(0, str.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
def append(str)
|
15
|
+
self.insert(-1, str.to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Date.parse sucks hard (assumes EU formatting, for one, does the wrong thing with 2 digit dates for two... etc.)
|
19
|
+
# so we have this here as our personal, bona-fide date parsing helper.
|
20
|
+
def to_date
|
21
|
+
us_format = /^([0-9]{1,2})[-\/\.]([0-9]{1,2})[-\/\.]([0-9]+)$/ # US standard MM/DD/YYYY, allowing for 2 digit year
|
22
|
+
db_format = /^([0-9]{4})[-\/\.]([0-9]{2})[-\/\.]([0-9]{2})$/ # More sane, but less common YYYY-MM-DD
|
23
|
+
|
24
|
+
if self.match(us_format)
|
25
|
+
m, d, y = self.extract(us_format)
|
26
|
+
elsif self.match(db_format)
|
27
|
+
y, m, d = self.extract(db_format)
|
28
|
+
else
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
y = y.to_i
|
33
|
+
if y < 100
|
34
|
+
# Ok, we'll let you do this 2 digit thing, but only because we like you.
|
35
|
+
# Assume that 10 years in the future is as far as we're interested in.
|
36
|
+
cutoff = Date.today.year - 2000 + 10
|
37
|
+
y += (y < cutoff) ? 2000 : 1900
|
38
|
+
end
|
39
|
+
Date.new(y,m.to_i,d.to_i) rescue nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the various captured elements from this string with the regex applied.
|
43
|
+
# Usage: a,b = 'abc123 is cool'.extract(/([a-z]*)([0-9]*)/)
|
44
|
+
# => a = 'abc', b = '123'
|
45
|
+
# With no capture in regex, returns full match
|
46
|
+
# If no match, returns nil
|
47
|
+
def extract(regex)
|
48
|
+
data = self.match(regex)
|
49
|
+
return nil unless data
|
50
|
+
if data.size > 2
|
51
|
+
return *(data.to_a[1..-1])
|
52
|
+
elsif data.size == 2
|
53
|
+
return data[1]
|
54
|
+
else
|
55
|
+
return data[0]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Simple parse-and-replace code, use eg: "My name is :name:".replace_vars(@person), will call #name on @person
|
60
|
+
# and insert into place of :name:. You can also pass in a hash to
|
61
|
+
# source the variable values, eg: "I like :food:!".replace_vars({:food => 'eggs'})
|
62
|
+
def replace_vars(obj)
|
63
|
+
self.gsub(/:([a-z0-9_]+):/) do |match|
|
64
|
+
verb = Regexp.last_match[1].intern
|
65
|
+
if obj.is_a?(Hash)
|
66
|
+
obj[verb].to_s
|
67
|
+
elsif obj.respond_to?(verb)
|
68
|
+
obj.send(verb).to_s
|
69
|
+
else
|
70
|
+
":#{verb}:"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# To a permalink-style string rep, removing all non-word characters and dasherizing all spaces
|
76
|
+
def to_dashcase
|
77
|
+
s = self.dup
|
78
|
+
s.gsub!(/\'/,'') # remove ' from rob's, so we don't get rob_s_blog
|
79
|
+
s.gsub!(/\W+/, ' ') # all non-word chars to spaces
|
80
|
+
s.strip! # ohh la la
|
81
|
+
s.downcase! #
|
82
|
+
s.gsub!(/\ +/, '-') # spaces to dashes, preferred separator char everywhere
|
83
|
+
s
|
84
|
+
end
|
85
|
+
alias_method :to_permalink, :to_dashcase
|
86
|
+
|
87
|
+
# def to_phone
|
88
|
+
# raw, suffix = self.strip.extract(/([0-9\(\)\- \.,]+)(.*)/)
|
89
|
+
# raw.gsub!(/[^0-9\+\,]+/,'')
|
90
|
+
# raw.gsub!(/^\+?1/, '')
|
91
|
+
# raw, pause = raw.extract(/([0-9]+)(.*)/)
|
92
|
+
# count = raw.length
|
93
|
+
# if count == 7 || count == 10
|
94
|
+
# area, first, last = raw.extract(/([0-9]{3})?([0-9]{3})([0-9]{4})/)
|
95
|
+
# area ||= Settings[:site][:phone].default_area_code || '919'
|
96
|
+
# suffix = ' ' + suffix unless suffix.blank?
|
97
|
+
# pattern = Settings[:site][:phone].format || '(area) first-last'
|
98
|
+
# res = pattern.sub('area', area).sub('first', first).sub('last', last) + pause + suffix
|
99
|
+
# return res
|
100
|
+
# else
|
101
|
+
# return self
|
102
|
+
# end
|
103
|
+
# end
|
104
|
+
|
105
|
+
def smart_truncate(len = 30, ending = '...')
|
106
|
+
len = Math.max(len, 5)
|
107
|
+
return self if self.length <= len
|
108
|
+
s = self[0...(len-2)].reverse
|
109
|
+
bits = s.split(/[\s\-,]/,2)
|
110
|
+
s = bits.length == 2 ? bits[1] : bits[0]
|
111
|
+
s.reverse + ending
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns an array that can be compared (eg via <=>) with another string's natural order
|
115
|
+
# to implement natural order sorting ("Bob123" => ['BOB', 123])
|
116
|
+
def natural_order(nocase=true)
|
117
|
+
i = true
|
118
|
+
str = self
|
119
|
+
str = str.upcase if nocase
|
120
|
+
str.gsub(/\s+/, '').split(/(\d+)/).map {|x| (i = !i) ? x.to_i : x}
|
121
|
+
end
|
122
|
+
|
123
|
+
# Intelligently pluralize a phrase, looking for an initial number and doing the right thing if it's found.
|
124
|
+
# Also handles ignoring punctuation.
|
125
|
+
# "Buy 2 widget!".smart_pluralize => "Buy 2 widgets!"
|
126
|
+
# Requires Rails or a pluralize method on string
|
127
|
+
if ''.respond_to?(:pluralize)
|
128
|
+
def smart_pluralize
|
129
|
+
amt, word = self.extract(/[^0-9\-]*(-?[0-9,]+)?.*(?:[^a-z]|^)([a-z]+)[^a-z]*$/i)
|
130
|
+
unless word.blank?
|
131
|
+
word = word.pluralize if amt.blank? || amt.gsub(',','').to_i != 1
|
132
|
+
return self.gsub(/([^a-z]|^)([a-z]+)([^a-z]*)$/i, '\1'+word+'\3')
|
133
|
+
end
|
134
|
+
return self
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Someday will be part of core ruby, with luck...
|
139
|
+
unless ''.respond_to?(:starts_with?)
|
140
|
+
# Does the string start with the specified +prefix+?
|
141
|
+
def starts_with?(prefix)
|
142
|
+
prefix = prefix.to_s
|
143
|
+
self[0, prefix.length] == prefix
|
144
|
+
end
|
145
|
+
|
146
|
+
# Does the string end with the specified +suffix+?
|
147
|
+
def ends_with?(suffix)
|
148
|
+
suffix = suffix.to_s
|
149
|
+
self[-suffix.length, suffix.length] == suffix
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# In case we're running in Rails, which defines this already...
|
154
|
+
unless ''.respond_to?(:constantize)
|
155
|
+
def constantize()
|
156
|
+
names = self.split('::')
|
157
|
+
names.shift if names.empty? || names.first.empty?
|
158
|
+
|
159
|
+
constant = Object
|
160
|
+
names.each do |name|
|
161
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
162
|
+
end
|
163
|
+
constant
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# When true, is a valid integer
|
168
|
+
def integer?
|
169
|
+
self.to_i.to_s == self
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
data/sample.rdoc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
describe Enumerable do
|
3
|
+
|
4
|
+
it 'should convert to a hash' do
|
5
|
+
[1,2,3].to_hash.should == {1 => nil, 2 => nil, 3 => nil}
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should accept a block to set hash values' do
|
9
|
+
[:a, :b, :c].to_hash {|k| k.to_s.upcase}.should == {:a => 'A', :b => 'B', :c => 'C'}
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
describe String do
|
3
|
+
|
4
|
+
describe 'when extracting' do
|
5
|
+
it 'should respond to extract' do
|
6
|
+
"test".should respond_to(:extract)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should return nil if extract fails to match' do
|
10
|
+
'test'.extract(/nossir/).should be_nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should extract a single value if the whole regex matches' do
|
14
|
+
res = 'test'.extract(/est/)
|
15
|
+
res.should be_a(String)
|
16
|
+
res.should == 'est'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should extract a single value correctly if a capture is specified' do
|
20
|
+
res = 'test'.extract(/e(s)t/)
|
21
|
+
res.should be_a(String)
|
22
|
+
res.should == 's'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should extract multiple values if more than one capture is specified' do
|
26
|
+
res = 'a great big number 10!'.extract(/(great).*(number).*([0-9]{2})/)
|
27
|
+
res.should be_an(Array)
|
28
|
+
res.should == ['great', 'number', '10']
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should extract nil for missing captures' do
|
32
|
+
a, b, c = 'a great big numero 10!'.extract(/(great).*(number)?.*([0-9]{2})/)
|
33
|
+
a.should == 'great'
|
34
|
+
b.should be_nil
|
35
|
+
c.should == '10'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should convert to a date correctly' do
|
40
|
+
{
|
41
|
+
'' => nil,
|
42
|
+
'13/1/2010' => nil,
|
43
|
+
'12/4/73' => Date.new(1973,12,4),
|
44
|
+
'12/4/1973' => Date.new(1973,12,4),
|
45
|
+
'12-31-10' => Date.new(2010,12,31),
|
46
|
+
'2025-01-04' => Date.new(2025,1,4)
|
47
|
+
}.each_pair do |str, date|
|
48
|
+
str.to_date.should == date
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should respond to ends_with?' do
|
53
|
+
'bob'.should respond_to(:ends_with?)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should correctly determine if it ends with a passed string' do
|
57
|
+
'bob'.ends_with?('ob').should be_true
|
58
|
+
'bob'.ends_with?('o').should_not be_true
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should be convertable to dashcase' do
|
62
|
+
"Rob's greatest hits!".to_dashcase.should == 'robs-greatest-hits'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should truncate intelligently' do
|
66
|
+
"A great big string o' doom!".smart_truncate(15).should == 'A great big...'
|
67
|
+
"Agreatbigstringodoom!".smart_truncate(15).should == 'Agreatbigstri...'
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should constantize correctly' do
|
71
|
+
'Object'.constantize.should equal(Object)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should constantize modules' do
|
75
|
+
'Enumerable'.constantize.should equal(Enumerable)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should support natural ordering' do
|
79
|
+
['a0', 'a90', 'a10', 'a9'].sort_by {|a| a.natural_order}.should == ['a0', 'a9', 'a10', 'a90']
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Require our library
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'iron', 'extensions'))
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
#config.add_formatter 'documentation'
|
6
|
+
config.color = true
|
7
|
+
config.backtrace_clean_patterns = [/rspec/]
|
8
|
+
end
|
9
|
+
|
data/version.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: iron-extensions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rob Morris
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-02 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &2152110960 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.6'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2152110960
|
25
|
+
description: Adds common extensions to core Ruby classes
|
26
|
+
email:
|
27
|
+
- rob@irongaze.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/iron/extensions/array.rb
|
33
|
+
- lib/iron/extensions/enumerable.rb
|
34
|
+
- lib/iron/extensions/file.rb
|
35
|
+
- lib/iron/extensions/fixnum.rb
|
36
|
+
- lib/iron/extensions/kernel.rb
|
37
|
+
- lib/iron/extensions/math.rb
|
38
|
+
- lib/iron/extensions/nil.rb
|
39
|
+
- lib/iron/extensions/numeric.rb
|
40
|
+
- lib/iron/extensions/object.rb
|
41
|
+
- lib/iron/extensions/range.rb
|
42
|
+
- lib/iron/extensions/regexp.rb
|
43
|
+
- lib/iron/extensions/string.rb
|
44
|
+
- lib/iron/extensions/symbol.rb
|
45
|
+
- lib/iron/extensions.rb
|
46
|
+
- spec/extensions/enumerable_spec.rb
|
47
|
+
- spec/extensions/object_spec.rb
|
48
|
+
- spec/extensions/string_spec.rb
|
49
|
+
- spec/spec_helper.rb
|
50
|
+
- LICENSE
|
51
|
+
- History.txt
|
52
|
+
- version.txt
|
53
|
+
- README.rdoc
|
54
|
+
- sample.rdoc
|
55
|
+
- .rspec
|
56
|
+
homepage: http://irongaze.com
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.9.2
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.8.10
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Extensions to core classes
|
81
|
+
test_files: []
|