rext 0.3.4
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/History.rdoc +97 -0
- data/Manifest +54 -0
- data/README.rdoc +136 -0
- data/Rakefile +16 -0
- data/benchmarks/enumerable.rb +14 -0
- data/benchmarks/proc.rb +24 -0
- data/lib/rext.rb +24 -0
- data/lib/rext/all.rb +18 -0
- data/lib/rext/array.rb +6 -0
- data/lib/rext/array/helpers.rb +64 -0
- data/lib/rext/date.rb +6 -0
- data/lib/rext/date/helpers.rb +11 -0
- data/lib/rext/enumerable.rb +6 -0
- data/lib/rext/enumerable/helpers.rb +88 -0
- data/lib/rext/hash.rb +6 -0
- data/lib/rext/hash/helpers.rb +42 -0
- data/lib/rext/integer.rb +6 -0
- data/lib/rext/integer/helpers.rb +29 -0
- data/lib/rext/module.rb +6 -0
- data/lib/rext/module/helpers.rb +85 -0
- data/lib/rext/numeric.rb +7 -0
- data/lib/rext/numeric/bytes.rb +16 -0
- data/lib/rext/numeric/time.rb +57 -0
- data/lib/rext/object.rb +7 -0
- data/lib/rext/object/helpers.rb +62 -0
- data/lib/rext/object/metaclass.rb +29 -0
- data/lib/rext/proc.rb +7 -0
- data/lib/rext/proc/helpers.rb +22 -0
- data/lib/rext/string.rb +7 -0
- data/lib/rext/string/encode.rb +82 -0
- data/lib/rext/string/helpers.rb +246 -0
- data/lib/rext/symbol.rb +6 -0
- data/lib/rext/symbol/helpers.rb +16 -0
- data/lib/rext/time.rb +6 -0
- data/lib/rext/time/helpers.rb +43 -0
- data/lib/rext/version.rb +4 -0
- data/rext.gemspec +30 -0
- data/spec/array_spec.rb +61 -0
- data/spec/date_spec.rb +14 -0
- data/spec/enumerable_spec.rb +55 -0
- data/spec/hash_spec.rb +36 -0
- data/spec/integer_spec.rb +19 -0
- data/spec/module_spec.rb +41 -0
- data/spec/numeric_spec.rb +31 -0
- data/spec/object_spec.rb +101 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/string_spec.rb +194 -0
- data/spec/symbol_spec.rb +14 -0
- data/spec/time_spec.rb +22 -0
- data/tasks/benchmark.rake +13 -0
- data/tasks/docs.rake +13 -0
- data/tasks/gemspec.rake +3 -0
- data/tasks/spec.rake +25 -0
- metadata +147 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
class Object
|
3
|
+
|
4
|
+
##
|
5
|
+
# Return the metaclass of this object.
|
6
|
+
|
7
|
+
def metaclass
|
8
|
+
class << self; self end
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Evaluate a +string+ or +block+ in context to this
|
13
|
+
# object metaclass.
|
14
|
+
|
15
|
+
def meta_eval string = nil, &block
|
16
|
+
return metaclass.class_eval(string) if string
|
17
|
+
metaclass.class_eval &block
|
18
|
+
end
|
19
|
+
alias :metaeval :meta_eval
|
20
|
+
|
21
|
+
##
|
22
|
+
# Define a singleton method.
|
23
|
+
|
24
|
+
def meta_def name, &block
|
25
|
+
meta_eval { define_method name, &block }
|
26
|
+
end
|
27
|
+
alias :metadef :meta_def
|
28
|
+
|
29
|
+
end
|
data/lib/rext/proc.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
class Proc
|
3
|
+
|
4
|
+
##
|
5
|
+
# Yield or instance evaluate the +object+ passed
|
6
|
+
# based on this proc's arity.
|
7
|
+
#
|
8
|
+
# === Examples
|
9
|
+
#
|
10
|
+
# def foo &block
|
11
|
+
# block.yield_or_eval 'bar'
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# foo { |v| v.length } # => 3
|
15
|
+
# foo { length } # => 3
|
16
|
+
#
|
17
|
+
|
18
|
+
def yield_or_eval object
|
19
|
+
arity > 0 ? self.call(object) : object.instance_eval(&self)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/rext/string.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
require 'rack'
|
3
|
+
require 'digest/sha2'
|
4
|
+
require 'digest/md5'
|
5
|
+
|
6
|
+
class String
|
7
|
+
|
8
|
+
##
|
9
|
+
# Return 32 character md5 string.
|
10
|
+
#
|
11
|
+
# === Examples
|
12
|
+
#
|
13
|
+
# 'test'.to_md5 # => 098f6bcd4621d373cade4e832627b4f6
|
14
|
+
#
|
15
|
+
|
16
|
+
def to_md5
|
17
|
+
::Digest::MD5.hexdigest self
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Return 128 character sha512 string.
|
22
|
+
#
|
23
|
+
# === Examples
|
24
|
+
#
|
25
|
+
# 'test'.to_sha512 # => ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff
|
26
|
+
#
|
27
|
+
|
28
|
+
def to_sha512
|
29
|
+
::Digest::SHA512.hexdigest self
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Return Base 64 decoded string.
|
34
|
+
#
|
35
|
+
# === Examples
|
36
|
+
#
|
37
|
+
# 'Y29va2llcw=='.base64_decode # => cookies
|
38
|
+
#
|
39
|
+
|
40
|
+
def base64_decode
|
41
|
+
unpack('m').first
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Return Base 64 encoded string.
|
46
|
+
#
|
47
|
+
# === Examples
|
48
|
+
#
|
49
|
+
# 'cookies'.base64_encode # => Y29va2llcw==
|
50
|
+
#
|
51
|
+
|
52
|
+
def base64_encode
|
53
|
+
[self].pack('m').chop
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# URL encode. Shortcut for Rack::Utils.encode.
|
58
|
+
|
59
|
+
def url_encode
|
60
|
+
Rack::Utils.escape self
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# URL decode. Shortcut for Rack::Utils.unescape.
|
65
|
+
|
66
|
+
def url_decode
|
67
|
+
Rack::Utils.unescape self
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Escape html entities. Shortcut for Rack::Utils.escape_html.
|
72
|
+
#
|
73
|
+
# === Examples
|
74
|
+
#
|
75
|
+
# 'im <strong>strong</strong>.escape_html # => im <strong>strong</strong>
|
76
|
+
#
|
77
|
+
|
78
|
+
def escape_html
|
79
|
+
Rack::Utils.escape_html self
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
|
2
|
+
require 'extlib'
|
3
|
+
|
4
|
+
class String
|
5
|
+
|
6
|
+
##
|
7
|
+
# Returns a File instance.
|
8
|
+
#
|
9
|
+
# === Examples
|
10
|
+
#
|
11
|
+
# 'History.rdoc'.file.mtime
|
12
|
+
#
|
13
|
+
|
14
|
+
def file
|
15
|
+
File.new self
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Returns a Pathname instance.
|
20
|
+
#
|
21
|
+
# === Examples
|
22
|
+
#
|
23
|
+
# 'lib'.path.join('foo').expand_path
|
24
|
+
#
|
25
|
+
|
26
|
+
def path
|
27
|
+
require 'pathname'
|
28
|
+
Pathname.new self
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Returns an array of files matching self.
|
33
|
+
#
|
34
|
+
# === Examples
|
35
|
+
#
|
36
|
+
# 'lib/**/*.rb'.files
|
37
|
+
#
|
38
|
+
|
39
|
+
def files
|
40
|
+
Dir[self]
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Merge the +word+ passed into the string. This
|
45
|
+
# is useful for adding classes which may already
|
46
|
+
# exist in a string.
|
47
|
+
#
|
48
|
+
# === Examples
|
49
|
+
#
|
50
|
+
# 'product'.merge_word('sold') # => "product sold"
|
51
|
+
# 'product sold'.merge_word('sold') # => "product sold"
|
52
|
+
#
|
53
|
+
|
54
|
+
def merge_word word
|
55
|
+
self << " #{word}" unless split.include? word
|
56
|
+
self
|
57
|
+
end
|
58
|
+
alias :add_class :merge_word
|
59
|
+
|
60
|
+
##
|
61
|
+
# Digitize a string.
|
62
|
+
#
|
63
|
+
# === Examples:
|
64
|
+
#
|
65
|
+
# '$100,000'.digitize # => 100000
|
66
|
+
#
|
67
|
+
|
68
|
+
def digitize
|
69
|
+
gsub /[^\d]/, ''
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Returns a constant when the string is a valid constant name.
|
74
|
+
|
75
|
+
def constantize
|
76
|
+
Extlib::Inflection.constantize self
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Convert a string to camel-case, and optionally +capitalize_first_letter+.
|
81
|
+
|
82
|
+
def camelize capitalize_first_letter = false
|
83
|
+
string = Extlib::Inflection.camelize(self)
|
84
|
+
return string if capitalize_first_letter
|
85
|
+
string[0,1] = string.first.downcase
|
86
|
+
string
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Wrap a string with a +prefix+ and optional
|
91
|
+
# +suffix+. When the +suffix+ is not present
|
92
|
+
# the +prefix+ will be used.
|
93
|
+
#
|
94
|
+
# === Examples
|
95
|
+
#
|
96
|
+
# 'foo'.wrap('|') # => |foo|
|
97
|
+
# 'foo'.wrap('(', ')') # => (foo)
|
98
|
+
#
|
99
|
+
|
100
|
+
def wrap prefix, suffix = nil
|
101
|
+
prefix + self + (suffix || prefix)
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Check if a string starts with another +string+.
|
106
|
+
#
|
107
|
+
# === Examples
|
108
|
+
#
|
109
|
+
# 'foo bar'.starts_with? 'foo' # => true
|
110
|
+
#
|
111
|
+
|
112
|
+
def starts_with? string
|
113
|
+
index(string) == 0
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Check if a string ends with another +string+.
|
118
|
+
#
|
119
|
+
# === Examples
|
120
|
+
#
|
121
|
+
# 'foo bar'.ends_with? 'bar' # => true
|
122
|
+
#
|
123
|
+
|
124
|
+
def ends_with? string
|
125
|
+
rindex(string) == length - string.length
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Determines if a string is plural.
|
130
|
+
#
|
131
|
+
# === Examples
|
132
|
+
#
|
133
|
+
# 'cookies'.plural? # => true
|
134
|
+
# 'cookie'.plural? # => false
|
135
|
+
#
|
136
|
+
|
137
|
+
def plural?
|
138
|
+
singular != self
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Determines if a string is singular.
|
143
|
+
#
|
144
|
+
# === Examples
|
145
|
+
#
|
146
|
+
# 'cookies'.singular? # => false
|
147
|
+
# 'cookie'.singular? # => true
|
148
|
+
#
|
149
|
+
|
150
|
+
def singular?
|
151
|
+
not plural?
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# First +n+ character(s).
|
156
|
+
#
|
157
|
+
# === Examples
|
158
|
+
#
|
159
|
+
# 'foo'.first # => f
|
160
|
+
# 'foo'.first(2) # => fo
|
161
|
+
#
|
162
|
+
|
163
|
+
def first n = 1
|
164
|
+
self[0, n]
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Last +n+ character(s).
|
169
|
+
#
|
170
|
+
# === Examples
|
171
|
+
#
|
172
|
+
# 'bar'.last # => r
|
173
|
+
# 'bar'.last(2) # => ar
|
174
|
+
#
|
175
|
+
|
176
|
+
def last n = 1
|
177
|
+
self[-n, n]
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# All characters after +n+.
|
182
|
+
#
|
183
|
+
# === Examples
|
184
|
+
#
|
185
|
+
# '.css'.from(1) #=> css
|
186
|
+
#
|
187
|
+
|
188
|
+
def from n
|
189
|
+
self[n, length]
|
190
|
+
end
|
191
|
+
|
192
|
+
##
|
193
|
+
# Replace all underscores with hyphens.
|
194
|
+
|
195
|
+
def dasherize
|
196
|
+
tr '_', '-'
|
197
|
+
end
|
198
|
+
|
199
|
+
##
|
200
|
+
# Return hash of word frequencies.
|
201
|
+
#
|
202
|
+
# === Examples
|
203
|
+
#
|
204
|
+
# 'foo foo bar'.word_frequency
|
205
|
+
# # => { 'foo' => 2, 'bar' => 1 }
|
206
|
+
#
|
207
|
+
|
208
|
+
def word_frequency
|
209
|
+
split.inject Hash.new(0) do |frequencies, word|
|
210
|
+
frequencies[word] += 1
|
211
|
+
frequencies
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
##
|
216
|
+
# Return frequency of _word_ or 0.
|
217
|
+
#
|
218
|
+
# === Examples
|
219
|
+
#
|
220
|
+
# 'foo foo bar'.frequency_of_word('foo') # => 2
|
221
|
+
# 'foo foo bar'.frequency_of_word('bar') # => 1
|
222
|
+
#
|
223
|
+
|
224
|
+
def frequency_of_word word
|
225
|
+
word_frequency[word]
|
226
|
+
end
|
227
|
+
|
228
|
+
class InvalidSwitchError < StandardError; end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Returns the switch equivilant of this string.
|
232
|
+
#
|
233
|
+
# === Examples
|
234
|
+
#
|
235
|
+
# 'foo_bar'.switchify # => --foo-bar
|
236
|
+
# 'lots_of_foobar'.switchify # => --lots-of-foobar
|
237
|
+
# 't'.switchify # => -t
|
238
|
+
# ''.switchify # => InvalidSwitchError
|
239
|
+
#
|
240
|
+
|
241
|
+
def switchify
|
242
|
+
raise InvalidSwitchError, 'switch must have a length > 0' if length.zero?
|
243
|
+
length > 1 ? "--#{dasherize}" : "-#{self}"
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
data/lib/rext/symbol.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
class Symbol
|
3
|
+
|
4
|
+
##
|
5
|
+
# Return a proc which sends itself as a message
|
6
|
+
# to the first proc argument.
|
7
|
+
#
|
8
|
+
# === Examples
|
9
|
+
#
|
10
|
+
# %w( some foo bar ).map(&:length) # => [4, 3, 3]
|
11
|
+
#
|
12
|
+
|
13
|
+
def to_proc
|
14
|
+
Proc.new { |object| object.send self }
|
15
|
+
end
|
16
|
+
end
|
data/lib/rext/time.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
class Time
|
3
|
+
|
4
|
+
def to_time #:nodoc:
|
5
|
+
self
|
6
|
+
end
|
7
|
+
|
8
|
+
##
|
9
|
+
# Time in words since +time+ or now.
|
10
|
+
#
|
11
|
+
# === Examples
|
12
|
+
#
|
13
|
+
# 5.seconds.ago.in_words_since_now # => less than one minute
|
14
|
+
# 5.days.ago.in_words_since_now # => 5 days
|
15
|
+
# 1.month.ago.in_words_since_now # => 1 month
|
16
|
+
# 101.years.ago.in_words_since_now # => hundreds of years
|
17
|
+
#
|
18
|
+
# "the article was published #{article.created_at.in_words_since_now} ago"
|
19
|
+
# # => the article was published 15 minutes ago
|
20
|
+
#
|
21
|
+
|
22
|
+
def in_words_since time = Time.now
|
23
|
+
return if self > time
|
24
|
+
seconds = (time - self).to_i
|
25
|
+
# TODO: abstract this out
|
26
|
+
pluralize = lambda do |type|
|
27
|
+
n = seconds.send(:"to_#{type}s")
|
28
|
+
n == 1 ? "one #{type}" : "#{n} #{type}s"
|
29
|
+
end
|
30
|
+
case seconds
|
31
|
+
when 0..59 ; 'less than one minute'
|
32
|
+
when 1.minute..59.minutes ; pluralize[:minute]
|
33
|
+
when 1.hour..23.hours ; pluralize[:hour]
|
34
|
+
when 1.day..6.days ; pluralize[:day]
|
35
|
+
when 1.week..3.weeks ; pluralize[:week]
|
36
|
+
when 1.month..11.months ; pluralize[:month]
|
37
|
+
when 1.year..99.years ; pluralize[:year]
|
38
|
+
else 'hundreds of years'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias :in_words_since_now :in_words_since
|
42
|
+
|
43
|
+
end
|