machinima_utils 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/array.rb +50 -0
- data/lib/class.rb +5 -0
- data/lib/falseclass.rb +5 -0
- data/lib/fixnum.rb +22 -0
- data/lib/http_utils.rb +29 -0
- data/lib/memcache.rb +193 -0
- data/lib/model.rb +75 -0
- data/lib/nil_class.rb +9 -0
- data/lib/object.rb +5 -0
- data/lib/remove_accents.rb +85 -0
- data/lib/string.rb +50 -0
- data/lib/trueclass.rb +5 -0
- metadata +15 -3
data/lib/array.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
class Array
|
2
|
+
def to_h
|
3
|
+
inject({}) { |h, v| h[v] = 1; h }
|
4
|
+
end
|
5
|
+
|
6
|
+
def map_with_index!
|
7
|
+
each_with_index do |e, idx|
|
8
|
+
self[idx] = yield(e, idx);
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def map_with_index(& block)
|
13
|
+
dup.map_with_index!(& block)
|
14
|
+
end
|
15
|
+
|
16
|
+
#performs a binary insert on the array (assumes the array is already sorted)
|
17
|
+
def binary_insert item
|
18
|
+
if item > last
|
19
|
+
push item
|
20
|
+
else
|
21
|
+
left_bound = 0
|
22
|
+
right_bound = size - 1
|
23
|
+
while left_bound < right_bound
|
24
|
+
middle_index = left_bound + (right_bound - left_bound) / 2
|
25
|
+
if item < self[middle_index]
|
26
|
+
right_bound = middle_index
|
27
|
+
elsif item > self[middle_index]
|
28
|
+
left_bound = middle_index+1
|
29
|
+
else
|
30
|
+
break
|
31
|
+
end
|
32
|
+
end
|
33
|
+
middle_index = left_bound if left_bound == right_bound
|
34
|
+
insert middle_index, item
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def indices_for_value value
|
39
|
+
indices = []
|
40
|
+
each_with_index do |v, i|
|
41
|
+
indices.push i if v == value
|
42
|
+
end
|
43
|
+
indices
|
44
|
+
end
|
45
|
+
|
46
|
+
def index_for_first_non_blank_value
|
47
|
+
each_with_index { |v, i| return i if v.present? }
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
end
|
data/lib/class.rb
ADDED
data/lib/falseclass.rb
ADDED
data/lib/fixnum.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
class Fixnum
|
2
|
+
def to_english
|
3
|
+
case self
|
4
|
+
when 0 then "zero"
|
5
|
+
when 1 then "one"
|
6
|
+
when 2 then "two"
|
7
|
+
when 3 then "three"
|
8
|
+
when 4 then "four"
|
9
|
+
when 5 then "five"
|
10
|
+
when 6 then "six"
|
11
|
+
when 7 then "seven"
|
12
|
+
when 8 then "eight"
|
13
|
+
when 9 then "nine"
|
14
|
+
when 10 then "ten"
|
15
|
+
else raise "to_english has not been implemented to convert #{self}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_bool
|
20
|
+
0 != self && nil != self ? true : false
|
21
|
+
end
|
22
|
+
end
|
data/lib/http_utils.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module HttpUtils
|
2
|
+
def self.http_get url
|
3
|
+
#if url.starts_with? 'https'
|
4
|
+
Net::HTTP.get_response(URI.parse(URI.escape(url)))
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.https_get url
|
8
|
+
uri = URI.parse(URI.escape(url))
|
9
|
+
logger.debug uri.inspect
|
10
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
11
|
+
http.use_ssl = true
|
12
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
13
|
+
|
14
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
15
|
+
|
16
|
+
response = http.request(request)
|
17
|
+
response
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.http_post url, params={}
|
21
|
+
Net::HTTP.post_form URI.parse(URI.escape(url)), params
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
#Code here
|
29
|
+
end
|
data/lib/memcache.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
if MEMCACHE['use_dalli']
|
2
|
+
module Dalli
|
3
|
+
class Client
|
4
|
+
def initialize(servers=nil, options={})
|
5
|
+
@servers = env_servers || servers || 'localhost:11211'
|
6
|
+
@options = {:expires_in => 0}.merge(options)
|
7
|
+
self.extend(Dalli::Client::MemcacheClientCompatibility) if Dalli::Client.compatibility_mode
|
8
|
+
end
|
9
|
+
|
10
|
+
@locks = {}
|
11
|
+
|
12
|
+
def lock_and_set key, value, expiry = 0, raw = false
|
13
|
+
acquire_lock key
|
14
|
+
set key, value, expiry, raw
|
15
|
+
release_lock key
|
16
|
+
end
|
17
|
+
|
18
|
+
def acquire_lock key
|
19
|
+
@locks ||= {}
|
20
|
+
return true if has_lock? key
|
21
|
+
|
22
|
+
# Keep trying to add the key to memcache
|
23
|
+
# Add returns false if the key is already in memcache
|
24
|
+
# Add is our test-and-set operation
|
25
|
+
while !add lock_key(key), 1
|
26
|
+
# We didn't get the lock, keep trying till we do
|
27
|
+
Thread.pass
|
28
|
+
end
|
29
|
+
@locks[key] = 1
|
30
|
+
end
|
31
|
+
|
32
|
+
def release_lock key
|
33
|
+
if has_lock? key
|
34
|
+
delete lock_key(key)
|
35
|
+
@locks.delete key
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_lock? key
|
40
|
+
@locks[key].present?
|
41
|
+
end
|
42
|
+
|
43
|
+
def lock_key name
|
44
|
+
"LOCK-#{@name}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Chokepoint method for instrumentation
|
48
|
+
def perform(op, key, * args)
|
49
|
+
retry_count = 0
|
50
|
+
key = key.to_s
|
51
|
+
validate_key(key)
|
52
|
+
key = key_with_namespace(key)
|
53
|
+
begin
|
54
|
+
server = ring.server_for_key(key)
|
55
|
+
server.request(op, key, * args)
|
56
|
+
# We rescue exception here, not NetworkError
|
57
|
+
rescue Exception => e
|
58
|
+
retry_count += 1
|
59
|
+
sleep(MEMCACHE['retry_sleep_interval'])
|
60
|
+
if retry_count < MEMCACHE['retry_count']
|
61
|
+
Dalli.logger.debug { e.message }
|
62
|
+
Dalli.logger.debug { "retrying request with new server" }
|
63
|
+
retry
|
64
|
+
else
|
65
|
+
raise "An Error occurred within Dalli and Memcached"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
else
|
74
|
+
class MemCache
|
75
|
+
def initialize(servers=nil, options={})
|
76
|
+
@servers = env_servers || servers || 'localhost:11211'
|
77
|
+
@options = {:expires_in => 0}.merge(options)
|
78
|
+
self.extend(Dalli::Client::MemcacheClientCompatibility) if Dalli::Client.compatibility_mode
|
79
|
+
end
|
80
|
+
|
81
|
+
@locks = {}
|
82
|
+
|
83
|
+
def lock_and_set key, value, expiry = 0, raw = false
|
84
|
+
acquire_lock key
|
85
|
+
set key, value, expiry, raw
|
86
|
+
release_lock key
|
87
|
+
end
|
88
|
+
|
89
|
+
def acquire_lock key
|
90
|
+
@locks ||= {}
|
91
|
+
return true if has_lock? key
|
92
|
+
|
93
|
+
# Keep trying to add the key to memcache
|
94
|
+
# Add returns false if the key is already in memcache
|
95
|
+
# Add is our test-and-set operation
|
96
|
+
while !add lock_key(key), 1
|
97
|
+
# We didn't get the lock, keep trying till we do
|
98
|
+
Thread.pass
|
99
|
+
end
|
100
|
+
@locks[key] = 1
|
101
|
+
end
|
102
|
+
|
103
|
+
def release_lock key
|
104
|
+
if has_lock? key
|
105
|
+
delete lock_key(key)
|
106
|
+
@locks.delete key
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def has_lock? key
|
111
|
+
@locks[key].present?
|
112
|
+
end
|
113
|
+
|
114
|
+
def lock_key name
|
115
|
+
"LOCK-#{@name}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
=begin
|
122
|
+
|
123
|
+
module Dalli
|
124
|
+
class Client
|
125
|
+
def initialize(servers=nil, options={})
|
126
|
+
@servers = env_servers || servers || 'localhost:11211'
|
127
|
+
@options = { :expires_in => 0 }.merge(options)
|
128
|
+
self.extend(Dalli::Client::MemcacheClientCompatibility) if Dalli::Client.compatibility_mode
|
129
|
+
end
|
130
|
+
|
131
|
+
@locks = {}
|
132
|
+
|
133
|
+
def lock_and_set key, value, expiry = 0, raw = false
|
134
|
+
acquire_lock key
|
135
|
+
set key, value, expiry, raw
|
136
|
+
release_lock key
|
137
|
+
end
|
138
|
+
|
139
|
+
def acquire_lock key
|
140
|
+
@locks ||= {}
|
141
|
+
return true if has_lock? key
|
142
|
+
|
143
|
+
# Keep trying to add the key to memcache
|
144
|
+
# Add returns false if the key is already in memcache
|
145
|
+
# Add is our test-and-set operation
|
146
|
+
while !add lock_key(key), 1
|
147
|
+
# We didn't get the lock, keep trying till we do
|
148
|
+
Thread.pass
|
149
|
+
end
|
150
|
+
@locks[key] = 1
|
151
|
+
end
|
152
|
+
|
153
|
+
def release_lock key
|
154
|
+
if has_lock? key
|
155
|
+
delete lock_key(key)
|
156
|
+
@locks.delete key
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def has_lock? key
|
161
|
+
@locks[key].present?
|
162
|
+
end
|
163
|
+
|
164
|
+
def lock_key name
|
165
|
+
"LOCK-#{@name}"
|
166
|
+
end
|
167
|
+
|
168
|
+
# Chokepoint method for instrumentation
|
169
|
+
def perform(op, key, *args)
|
170
|
+
retry_count = 0
|
171
|
+
key = key.to_s
|
172
|
+
validate_key(key)
|
173
|
+
key = key_with_namespace(key)
|
174
|
+
begin
|
175
|
+
server = ring.server_for_key(key)
|
176
|
+
server.request(op, key, *args)
|
177
|
+
# We rescue exception here, not NetworkError
|
178
|
+
rescue Exception => e
|
179
|
+
retry_count += 1
|
180
|
+
sleep(MEMCACHE['retry_sleep_interval'])
|
181
|
+
if retry_count < MEMCACHE['retry_count']
|
182
|
+
Dalli.logger.debug { e.message }
|
183
|
+
Dalli.logger.debug { "retrying request with new server" }
|
184
|
+
retry
|
185
|
+
else
|
186
|
+
raise "An Error occurred within Dalli and Memcached"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
=end
|
data/lib/model.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Sequel
|
2
|
+
|
3
|
+
|
4
|
+
class ValidationException < RuntimeError
|
5
|
+
attr_reader :validation_errors
|
6
|
+
|
7
|
+
def initialize(validation_errors)
|
8
|
+
@validation_errors = validation_errors
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
class Model
|
15
|
+
if MEMCACHE['session_enabled'] && MEMCACHE['model_caching_enabled'] == true
|
16
|
+
Sequel::Model.plugin :caching, CACHE, :ttl => MEMCACHE['model_cache_ttl']
|
17
|
+
end
|
18
|
+
Sequel::Model.plugin :json_serializer
|
19
|
+
Sequel::Model.plugin :association_dependencies
|
20
|
+
Sequel::Model.plugin :validation_helpers
|
21
|
+
Sequel::Model.plugin :timestamps, :update_on_create => true
|
22
|
+
|
23
|
+
def save!
|
24
|
+
success = save
|
25
|
+
if !success
|
26
|
+
raise ValidationException.new(errors), "Could not save model due to failing validation: #{errors.inspect}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.create! attributes={}
|
31
|
+
instance = self.new attributes
|
32
|
+
instance.save!
|
33
|
+
instance
|
34
|
+
end
|
35
|
+
|
36
|
+
def memcached?
|
37
|
+
MEMCACHE['session_enabled'] && MEMCACHE['model_caching_enabled'] && CACHE.get(cache_key).present?
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.reload model
|
41
|
+
model.class[model.id] rescue model.class.filter(:id => model.id).first
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def cached_association_id_key association
|
46
|
+
"#{self.class.name}_#{id}_#{association}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_cached_association association
|
50
|
+
if MEMCACHE['session_enabled'] == true
|
51
|
+
cached_association = send association.to_sym, false
|
52
|
+
cached_association_id = cached_association.present?? cached_association.id : -1
|
53
|
+
CACHE.set cached_association_id_key(association), cached_association_id
|
54
|
+
cached_association_id
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_cached_associations *associations
|
59
|
+
associations.each{ |association | update_cached_association association }
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_cached_association association
|
63
|
+
return send(association.to_sym, false) if MEMCACHE['session_enabled'] != true
|
64
|
+
cached_association_id = CACHE.get cached_association_id_key(association)
|
65
|
+
if cached_association_id.nil?
|
66
|
+
cached_association_id = update_cached_association association
|
67
|
+
end
|
68
|
+
if -1 == cached_association_id
|
69
|
+
nil
|
70
|
+
else
|
71
|
+
association.to_upper_camelcase.constantize[cached_association_id]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/nil_class.rb
ADDED
data/lib/object.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# RemoveAccents version 1.0.3 (c) 2008-2009 Solutions Informatiques Techniconseils inc.
|
2
|
+
#
|
3
|
+
# This module adds 2 methods to the string class.
|
4
|
+
# Up-to-date version and documentation available at:
|
5
|
+
#
|
6
|
+
# http://www.techniconseils.ca/en/scripts-remove-accents-ruby.php
|
7
|
+
#
|
8
|
+
# This script is available under the following license :
|
9
|
+
# Creative Commons Attribution-Share Alike 2.5.
|
10
|
+
#
|
11
|
+
# See full license and details at :
|
12
|
+
# http://creativecommons.org/licenses/by-sa/2.5/ca/
|
13
|
+
#
|
14
|
+
# Version history:
|
15
|
+
# * 1.0.3 : July 23 2009
|
16
|
+
# Corrected some incorrect character codes. Source is now wikipedia at:
|
17
|
+
# http://en.wikipedia.org/wiki/ISO/IEC_8859-1#Related_character_maps
|
18
|
+
# Thanks to Raimon Fernandez for pointing out the incorrect codes.
|
19
|
+
# * 1.0.2 : October 29 2008
|
20
|
+
# Slightly optimized version of urlize - Jonathan Grenier (jgrenier@techniconseils.ca)
|
21
|
+
# * 1.0.1 : October 29 2008
|
22
|
+
# First public revision - Jonathan Grenier (jgrenier@techniconseils.ca)
|
23
|
+
#
|
24
|
+
|
25
|
+
class String
|
26
|
+
# The extended characters map used by removeaccents. The accented characters
|
27
|
+
# are coded here using their numerical equivalent to sidestep encoding issues.
|
28
|
+
# These correspond to ISO-8859-1 encoding.
|
29
|
+
ACCENTS_MAPPING = {
|
30
|
+
'E' => [200,201,202,203],
|
31
|
+
'e' => [232,233,234,235],
|
32
|
+
'A' => [192,193,194,195,196,197],
|
33
|
+
'a' => [224,225,226,227,228,229,230],
|
34
|
+
'C' => [199],
|
35
|
+
'c' => [231],
|
36
|
+
'O' => [210,211,212,213,214,216],
|
37
|
+
'o' => [242,243,244,245,246,248],
|
38
|
+
'I' => [204,205,206,207],
|
39
|
+
'i' => [236,237,238,239],
|
40
|
+
'U' => [217,218,219,220],
|
41
|
+
'u' => [249,250,251,252],
|
42
|
+
'N' => [209],
|
43
|
+
'n' => [241],
|
44
|
+
'Y' => [221],
|
45
|
+
'y' => [253,255],
|
46
|
+
'AE' => [306],
|
47
|
+
'ae' => [346],
|
48
|
+
'OE' => [188],
|
49
|
+
'oe' => [189]
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
# Remove the accents from the string. Uses String::ACCENTS_MAPPING as the source map.
|
54
|
+
def removeaccents
|
55
|
+
str = String.new(self)
|
56
|
+
String::ACCENTS_MAPPING.each {|letter,accents|
|
57
|
+
packed = accents.pack('U*')
|
58
|
+
rxp = Regexp.new("[#{packed}]", nil, 'U')
|
59
|
+
str.gsub!(rxp, letter)
|
60
|
+
}
|
61
|
+
|
62
|
+
str
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Convert a string to a format suitable for a URL without ever using escaped characters.
|
67
|
+
# It calls strip, removeaccents, downcase (optional) then removes the spaces (optional)
|
68
|
+
# and finally removes any characters matching the default regexp (/[^-_A-Za-z0-9]/).
|
69
|
+
#
|
70
|
+
# Options
|
71
|
+
#
|
72
|
+
# * :downcase => call downcase on the string (defaults to true)
|
73
|
+
# * :convert_spaces => Convert space to underscore (defaults to false)
|
74
|
+
# * :regexp => The regexp matching characters that will be converting to an empty string (defaults to /[^-_A-Za-z0-9]/)
|
75
|
+
def urlize(options = {})
|
76
|
+
options[:downcase] ||= true
|
77
|
+
options[:convert_spaces] ||= false
|
78
|
+
options[:regexp] ||= /[^-_A-Za-z0-9]/
|
79
|
+
|
80
|
+
str = self.strip.removeaccents
|
81
|
+
str.downcase! if options[:downcase]
|
82
|
+
str.gsub!(/\ /,'_') if options[:convert_spaces]
|
83
|
+
str.gsub(options[:regexp], '')
|
84
|
+
end
|
85
|
+
end
|
data/lib/string.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
class String
|
2
|
+
def self.random_alphanumeric_string( length, options = {} )
|
3
|
+
valid_chars = []
|
4
|
+
valid_chars += ("A"[0].."Z"[0]).to_a if options[:include_upper_case].nil? || options[:include_upper_case]
|
5
|
+
valid_chars += ("a"[0].."z"[0]).to_a if options[:include_lower_case].nil? || options[:include_lower_case]
|
6
|
+
valid_chars += ("0"[0].."9"[0]).to_a if options[:include_numbers].nil? || options[:include_numbers]
|
7
|
+
str = ""
|
8
|
+
length.times{ str += valid_chars[rand(valid_chars.size)].chr }
|
9
|
+
str
|
10
|
+
end
|
11
|
+
|
12
|
+
def strip_javascript
|
13
|
+
gsub(/<script.*?>[\s\S]*<\/script>/i, "")
|
14
|
+
end
|
15
|
+
|
16
|
+
def strip_html
|
17
|
+
gsub %r{</?[^>]+?>}, ''
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_bool
|
21
|
+
downcased_str = downcase
|
22
|
+
if [true, 'true', 1, '1', 'T', 't'].include?( downcased_str )
|
23
|
+
true
|
24
|
+
elsif [false, 'false', 0, '0', 'F', 'f'].include?( downcased_str )
|
25
|
+
false
|
26
|
+
else
|
27
|
+
raise "string with value #{self} is not convertible to boolean"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def html_escape
|
32
|
+
gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<")
|
33
|
+
end
|
34
|
+
|
35
|
+
def truncate options={}
|
36
|
+
options.reverse_merge!(:length => 30, :omission => "...")
|
37
|
+
len = options[:length] - options[:omission].length
|
38
|
+
chars = to_s
|
39
|
+
(chars.length > options[:length] ? chars[0...len] + options[:omission] : to_s).to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
#converts a snake case string to upper camel case
|
43
|
+
def to_upper_camelcase
|
44
|
+
split_word_array = split '_'
|
45
|
+
for word in split_word_array
|
46
|
+
word[0] = word[0].chr.capitalize
|
47
|
+
end
|
48
|
+
split_word_array.join
|
49
|
+
end
|
50
|
+
end
|
data/lib/trueclass.rb
ADDED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: machinima_utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Machinima
|
@@ -28,6 +28,8 @@ extensions: []
|
|
28
28
|
extra_rdoc_files: []
|
29
29
|
|
30
30
|
files:
|
31
|
+
- lib/array.rb
|
32
|
+
- lib/class.rb
|
31
33
|
- lib/extensions/array.rb
|
32
34
|
- lib/extensions/class.rb
|
33
35
|
- lib/extensions/falseclass.rb
|
@@ -39,7 +41,17 @@ files:
|
|
39
41
|
- lib/extensions/remove_accents.rb
|
40
42
|
- lib/extensions/string.rb
|
41
43
|
- lib/extensions/trueclass.rb
|
44
|
+
- lib/falseclass.rb
|
45
|
+
- lib/fixnum.rb
|
46
|
+
- lib/http_utils.rb
|
42
47
|
- lib/HttpUtils/http_utils.rb
|
48
|
+
- lib/memcache.rb
|
49
|
+
- lib/model.rb
|
50
|
+
- lib/nil_class.rb
|
51
|
+
- lib/object.rb
|
52
|
+
- lib/remove_accents.rb
|
53
|
+
- lib/string.rb
|
54
|
+
- lib/trueclass.rb
|
43
55
|
has_rdoc: true
|
44
56
|
homepage:
|
45
57
|
licenses: []
|