iron-extensions 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|