mack-facets 0.6.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/README +3 -0
- data/lib/english_extensions/inflect.rb +50 -0
- data/lib/english_extensions/numerals.rb +12 -0
- data/lib/extensions/array.rb +90 -0
- data/lib/extensions/class.rb +38 -0
- data/lib/extensions/hash.rb +49 -0
- data/lib/extensions/kernel.rb +34 -0
- data/lib/extensions/math.rb +15 -0
- data/lib/extensions/module.rb +29 -0
- data/lib/extensions/object.rb +164 -0
- data/lib/extensions/string.rb +218 -0
- data/lib/extensions/symbol.rb +7 -0
- data/lib/mack-facets.rb +31 -0
- data/lib/utils/inflections.rb +63 -0
- data/lib/utils/inflector.rb +99 -0
- data/lib/utils/options_merger.rb +27 -0
- metadata +86 -0
data/README
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module English # :nodoc:
|
2
|
+
|
3
|
+
# = English Nouns Number Inflection.
|
4
|
+
#
|
5
|
+
# This module provides english singular <-> plural noun inflections.
|
6
|
+
module Inflect # :nodoc:
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# Convert an English word from plurel to singular.
|
11
|
+
#
|
12
|
+
# "boys".singular #=> boy
|
13
|
+
# "tomatoes".singular #=> tomato
|
14
|
+
#
|
15
|
+
def singular(word)
|
16
|
+
if result = singular_of[word]
|
17
|
+
return result.dup
|
18
|
+
end
|
19
|
+
result = word.dup
|
20
|
+
singularization_rules.each do |(match, replacement)|
|
21
|
+
break if result.gsub!(match, replacement)
|
22
|
+
end
|
23
|
+
# Mack: cache the result of the translation:
|
24
|
+
singular_of[word] = result unless word == result
|
25
|
+
return result
|
26
|
+
end
|
27
|
+
|
28
|
+
# Convert an English word from singular to plurel.
|
29
|
+
#
|
30
|
+
# "boy".plural #=> boys
|
31
|
+
# "tomato".plural #=> tomatoes
|
32
|
+
#
|
33
|
+
def plural(word)
|
34
|
+
if result = plural_of[word]
|
35
|
+
return result.dup
|
36
|
+
end
|
37
|
+
#return self.dup if /s$/ =~ self # ???
|
38
|
+
result = word.dup
|
39
|
+
pluralization_rules.each do |(match, replacement)|
|
40
|
+
break if result.gsub!(match, replacement)
|
41
|
+
end
|
42
|
+
# Mack: cache the result of the translation:
|
43
|
+
plural_of[word] = result unless word == result
|
44
|
+
return result
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
class Array
|
2
|
+
|
3
|
+
# This method is useful when you have a method that looks like this:
|
4
|
+
# def foo(*args)
|
5
|
+
# do something
|
6
|
+
# end
|
7
|
+
# The problem is when you use the * like that everything that comes in is
|
8
|
+
# an array. Here are a few problems with this:
|
9
|
+
# foo([1,2,3])
|
10
|
+
# When you pass an array into this type of method you get the following nested array:
|
11
|
+
# [[1,2,3]]
|
12
|
+
# The parse_splat_args method, if called, would do this:
|
13
|
+
# args.parse_splat_args # => [1,2,3]
|
14
|
+
# Now say you called this method like such:
|
15
|
+
# foo(1)
|
16
|
+
# args would be [1]
|
17
|
+
# args.parse_splat_args # => 1
|
18
|
+
# Finally
|
19
|
+
# foo
|
20
|
+
# args.parse_splat_args # => nil
|
21
|
+
def parse_splat_args
|
22
|
+
unless self.empty?
|
23
|
+
args = self#.flatten
|
24
|
+
case args.size
|
25
|
+
when 1
|
26
|
+
return args.first # if there was only one arg passed, return just that, without the array
|
27
|
+
when 0
|
28
|
+
return nil # if no args were passed return nil
|
29
|
+
else
|
30
|
+
return args # else return the array back, cause chances are that's what they passed you!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# This will return a new instance of the array sorted randomly.
|
36
|
+
def randomize(&block)
|
37
|
+
if block_given?
|
38
|
+
self.sort {|x,y| yield x, y}
|
39
|
+
else
|
40
|
+
self.sort_by { rand }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# This calls the randomize method, but will permantly replace the existing array.
|
45
|
+
def randomize!(&block)
|
46
|
+
if block_given?
|
47
|
+
self.replace(self.randomize(&block))
|
48
|
+
else
|
49
|
+
self.replace(self.randomize)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# This will pick a random value from the array
|
54
|
+
def pick_random
|
55
|
+
self[rand(self.length)]
|
56
|
+
end
|
57
|
+
|
58
|
+
# This allows you to easily recurse of the array randomly.
|
59
|
+
def random_each
|
60
|
+
self.randomize.each {|x| yield x}
|
61
|
+
end
|
62
|
+
|
63
|
+
def subset?(other)
|
64
|
+
self.each do |x|
|
65
|
+
return false if !(other.include? x)
|
66
|
+
end
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def superset?(other)
|
71
|
+
other.subset?(self)
|
72
|
+
end
|
73
|
+
|
74
|
+
# This will give you a count, as a Hash, of all the values in the Array.
|
75
|
+
# %w{spam spam eggs ham eggs spam}.count # => {"eggs" => 2, "ham" => 1, "spam" => 3}
|
76
|
+
def count
|
77
|
+
k = Hash.new(0)
|
78
|
+
self.each{|x| k[x] += 1}
|
79
|
+
k
|
80
|
+
end
|
81
|
+
|
82
|
+
# This will invert the index and the values and return a Hash of the results.
|
83
|
+
# %w{red yellow orange}.invert # => {"red" => 0, "orange" => 2, "yellow" => 1}
|
84
|
+
def invert
|
85
|
+
h = {}
|
86
|
+
self.each_with_index{|x,i| h[x] = i}
|
87
|
+
h
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Class
|
2
|
+
|
3
|
+
# Returns a new Object instance of the class name specified.
|
4
|
+
#
|
5
|
+
# Examples:
|
6
|
+
# Class.new_instance_of("Orange") => #<Orange:0x376c0c>
|
7
|
+
# Class.new_instance_of("Animals::Dog") => #<Animals::Dog:0x376a2c>
|
8
|
+
def self.new_instance_of(klass_name)
|
9
|
+
klass_name.constantize.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# This will through the ancestor tree of object and tell you if
|
13
|
+
# that object is of the specified type.
|
14
|
+
def class_is_a?(klass_name)
|
15
|
+
self.ancestors.each do |an|
|
16
|
+
if an == klass_name
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns an array of the classes parent classes.
|
24
|
+
#
|
25
|
+
# Examples:
|
26
|
+
# Orange.parents # => [Citrus, Fruit, Object]
|
27
|
+
# Citrus.parents # => [Fruit, Object]
|
28
|
+
# Fruit.parents # => [Object]
|
29
|
+
def parents
|
30
|
+
ans = [self.superclass]
|
31
|
+
until ans.last.superclass.nil?
|
32
|
+
ans << ans.last.superclass
|
33
|
+
end
|
34
|
+
ans
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'uri'
|
2
|
+
class Hash
|
3
|
+
|
4
|
+
def join(pair_string, join_string)
|
5
|
+
output = []
|
6
|
+
sorted = self.sort {|a,b| a[0].to_s <=> b[0].to_s}
|
7
|
+
sorted.each do |ar|
|
8
|
+
output << sprintf(pair_string, ar[0], ar[1])
|
9
|
+
end
|
10
|
+
output.join(join_string)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Deletes the key(s) passed in from the hash.
|
14
|
+
def -(ars)
|
15
|
+
[ars].flatten.each {|a| self.delete(a)}
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
# Converts a hash to query string parameters.
|
20
|
+
# An optional boolean escapes the values if true, which is the default.
|
21
|
+
def to_params(escape = true)
|
22
|
+
params = ''
|
23
|
+
stack = []
|
24
|
+
|
25
|
+
each do |k, v|
|
26
|
+
if v.is_a?(Hash)
|
27
|
+
stack << [k,v]
|
28
|
+
else
|
29
|
+
v = v.to_s.uri_escape if escape
|
30
|
+
params << "#{k}=#{v}&"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
stack.each do |parent, hash|
|
35
|
+
hash.each do |k, v|
|
36
|
+
if v.is_a?(Hash)
|
37
|
+
stack << ["#{parent}[#{k}]", v]
|
38
|
+
else
|
39
|
+
v = v.to_s.uri_escape if escape
|
40
|
+
params << "#{parent}[#{k}]=#{v}&"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
params.chop! # trailing &
|
46
|
+
params.split("&").sort.join("&")
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Kernel
|
5
|
+
|
6
|
+
def pp_to_s(object)
|
7
|
+
pp_out = StringIO.new
|
8
|
+
PP.pp(object,pp_out)
|
9
|
+
return pp_out.string
|
10
|
+
end
|
11
|
+
|
12
|
+
def retryable(options = {}, &block)
|
13
|
+
opts = { :tries => 1, :on => Exception }.merge(options)
|
14
|
+
|
15
|
+
retries = opts[:tries]
|
16
|
+
retry_exceptions = [opts[:on]].flatten
|
17
|
+
|
18
|
+
x = %{
|
19
|
+
begin
|
20
|
+
return yield
|
21
|
+
rescue #{retry_exceptions.join(", ")} => e
|
22
|
+
retries -= 1
|
23
|
+
if retries > 0
|
24
|
+
retry
|
25
|
+
else
|
26
|
+
raise e
|
27
|
+
end
|
28
|
+
end
|
29
|
+
}
|
30
|
+
|
31
|
+
eval(x, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Module
|
2
|
+
|
3
|
+
# Bulk converts the security level of methods in this Module from one level to another.
|
4
|
+
def convert_security_of_methods(old_level = :public, new_level = :protected)
|
5
|
+
eval("#{old_level}_instance_methods").each{ |meth| self.send(new_level, meth) }
|
6
|
+
self
|
7
|
+
end
|
8
|
+
|
9
|
+
# Includes this module into a Class, and changes all public methods to protected.
|
10
|
+
#
|
11
|
+
# Examples:
|
12
|
+
# module MyCoolUtils
|
13
|
+
# def some_meth
|
14
|
+
# "hi"
|
15
|
+
# end
|
16
|
+
# self.include_safely_into(FooController)
|
17
|
+
# end
|
18
|
+
# or:
|
19
|
+
# MyCoolUtils.include_safely_into(FooController, SomeOtherClass)
|
20
|
+
def include_safely_into(*args)
|
21
|
+
[args].flatten.each do |a|
|
22
|
+
if a.is_a?(String) || a.is_a?(Symbol)
|
23
|
+
a = a.to_s.constantize
|
24
|
+
end
|
25
|
+
a.send(:include, self.convert_security_of_methods)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
# Includes a module into the current Class, and changes all the module's public methods to protected.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
# class FooController
|
7
|
+
# safely_include_module(MyCoolUtils, MyOtherModule)
|
8
|
+
# end
|
9
|
+
def safely_include_module(*modules)
|
10
|
+
[modules].flatten.each do |mod|
|
11
|
+
mod.include_safely_into(self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Prints out the methods associated with this object in alphabetical order.
|
16
|
+
def print_methods
|
17
|
+
m = "----- #{self} (methods) -----\n"
|
18
|
+
m << methods.sort.join("\n")
|
19
|
+
puts m
|
20
|
+
m
|
21
|
+
end
|
22
|
+
|
23
|
+
# An elegant way to refactor out common options
|
24
|
+
#
|
25
|
+
# with_options :order => 'created_at', :class_name => 'Comment' do |post|
|
26
|
+
# post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
|
27
|
+
# post.has_many :unapproved_comments, :conditions => ['approved = ?', false]
|
28
|
+
# post.has_many :all_comments
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# Can also be used with an explicit receiver:
|
32
|
+
#
|
33
|
+
# map.with_options :controller => "people" do |people|
|
34
|
+
# people.connect "/people", :action => "index"
|
35
|
+
# people.connect "/people/:id", :action => "show"
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
def with_options(options)
|
39
|
+
yield Mack::Utils::OptionMerger.new(self, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
# See Class parents for more information.
|
43
|
+
def class_parents
|
44
|
+
self.class.parents
|
45
|
+
end
|
46
|
+
|
47
|
+
# This method gets called when a parameter is passed into a named route.
|
48
|
+
# This can be overridden in an Object to provlde custom handling of parameters.
|
49
|
+
def to_param
|
50
|
+
self.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
# Uses <code>define_method</code> to create an empty for the method parameter defined.
|
54
|
+
# That method will then raise MethodNotImplemented. This is useful for creating interfaces
|
55
|
+
# and you want to stub out methods that others need to implement.
|
56
|
+
def self.needs_method(meth)
|
57
|
+
define_method(meth) do
|
58
|
+
raise NoMethodError.new("The interface you are using requires you define the following method '#{meth}'")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# This prints out running time for the block provided. This is great for things
|
63
|
+
# like Rake tasks, etc... where you would like to know how long it, or a section of
|
64
|
+
# it took to run.
|
65
|
+
def running_time(message = "", logger = nil)
|
66
|
+
s_time = Time.now
|
67
|
+
s = "---Starting at #{s_time}---"
|
68
|
+
puts s
|
69
|
+
logger.info s unless logger.nil?
|
70
|
+
yield if block_given?
|
71
|
+
e_time = Time.now
|
72
|
+
e = "---Ending at #{e_time}---"
|
73
|
+
puts e
|
74
|
+
logger.info e unless logger.nil?
|
75
|
+
secs = e_time - s_time
|
76
|
+
if secs < 60
|
77
|
+
x = "Running time #{secs} seconds."
|
78
|
+
else
|
79
|
+
x = "Running time roughly #{secs/60} minutes [#{secs} seconds]"
|
80
|
+
end
|
81
|
+
x += " [MESSAGE]: #{message}" unless message.blank?
|
82
|
+
puts x
|
83
|
+
logger.info x unless logger.nil?
|
84
|
+
end
|
85
|
+
|
86
|
+
# This method will call send to all the methods defined on the previous method.
|
87
|
+
#
|
88
|
+
# Example:
|
89
|
+
# Fruit.send_with_chain([:new, :get_citrus, :get_orange, :class]) # => Orange
|
90
|
+
#
|
91
|
+
# This would be the equivalent:
|
92
|
+
# Fruit.new.get_citrus.get_orange.class
|
93
|
+
def send_with_chain(methods, *args)
|
94
|
+
obj = self
|
95
|
+
[methods].flatten.each {|m| obj = obj.send(m, *args)}
|
96
|
+
obj
|
97
|
+
end
|
98
|
+
|
99
|
+
# ivar_cache allows you to cache the results of the block into an instance variable in a class,
|
100
|
+
# and then will serve up that instance variable the next time you call that method again.
|
101
|
+
#
|
102
|
+
# old way:
|
103
|
+
# def show_page_link
|
104
|
+
# unless @show_page_link # check if instance variable exists
|
105
|
+
# # if the instance variable doesn't exist let's do some work and assign it to the instance variable.
|
106
|
+
# @show_page_link = link_to("show", some_url(:id => self.id, :foo => bar, etc... => etc))
|
107
|
+
# end
|
108
|
+
# @show_page_link # now return the instance variable
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# new way:
|
112
|
+
# def show_page_link
|
113
|
+
# ivar_cache do
|
114
|
+
# link_to("show", some_url(:id => self.id, :foo => bar, etc... => etc))
|
115
|
+
# end
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# this does everything the old way did, but it is much cleaner, and a lot less code!
|
119
|
+
# in case you're wondering it caches the result, by default, to an instance variable named after the method,
|
120
|
+
# so in our above example the instance variable would be name, <code>@show_page_link</code>. this can be overridden like such:
|
121
|
+
#
|
122
|
+
# def show_page_link
|
123
|
+
# ivar_cache("foo_var") do
|
124
|
+
# link_to("show", some_url(:id => self.id, :foo => bar, etc... => etc))
|
125
|
+
# end
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# now it will cache it to <code>@foo_var</code>
|
129
|
+
def ivar_cache(var_name = nil, &block)
|
130
|
+
if var_name.nil?
|
131
|
+
call = caller[0]
|
132
|
+
var_name = call[(call.index('`')+1)...call.index("'")]
|
133
|
+
end
|
134
|
+
var = instance_variable_get("@#{var_name}")
|
135
|
+
unless var
|
136
|
+
return instance_variable_set("@#{var_name}", yield) if block_given?
|
137
|
+
end
|
138
|
+
instance_variable_get("@#{var_name}")
|
139
|
+
end
|
140
|
+
|
141
|
+
def ivar_cache_clear(var_name = nil, &block)
|
142
|
+
if var_name.nil?
|
143
|
+
call = caller[0]
|
144
|
+
var_name = call[(call.index('`')+1)...call.index("'")]
|
145
|
+
end
|
146
|
+
remove_instance_variable("@#{var_name}") #rescue
|
147
|
+
yield if block_given?
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns the namespaces for a particular object.
|
151
|
+
#
|
152
|
+
# Examples:
|
153
|
+
# Animals::Dog::Poodle.new.namespaces # => ["Animals", "Dog"]
|
154
|
+
def namespaces
|
155
|
+
ivar_cache("object_namespaces") do
|
156
|
+
nss = []
|
157
|
+
full_name = self.class.name.to_s
|
158
|
+
nss = full_name.split("::")
|
159
|
+
nss.pop
|
160
|
+
nss
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
class String
|
2
|
+
include Style
|
3
|
+
|
4
|
+
def methodize
|
5
|
+
x = self
|
6
|
+
|
7
|
+
# if we get down to a nil or an empty string raise an exception!
|
8
|
+
raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
|
9
|
+
|
10
|
+
# get rid of the big stuff in the front/back
|
11
|
+
x.strip!
|
12
|
+
|
13
|
+
# if we get down to a nil or an empty string raise an exception!
|
14
|
+
raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
|
15
|
+
|
16
|
+
x = x.underscore
|
17
|
+
|
18
|
+
# get rid of spaces and make the _
|
19
|
+
x.gsub!(' ', '_')
|
20
|
+
# get rid of everything that isn't 'safe' a-z, 0-9, ?, !, =, _
|
21
|
+
x.gsub!(/([^ a-zA-Z0-9\_\?\!\=]+)/n, '_')
|
22
|
+
|
23
|
+
# if we get down to a nil or an empty string raise an exception!
|
24
|
+
raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
|
25
|
+
|
26
|
+
# condense multiple 'safe' non a-z chars to just one.
|
27
|
+
# ie. ___ becomes _ !!!! becomes ! etc...
|
28
|
+
[' ', '_', '?', '!', "="].each do |c|
|
29
|
+
x.squeeze!(c)
|
30
|
+
end
|
31
|
+
|
32
|
+
# if we get down to a nil or an empty string raise an exception!
|
33
|
+
raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
|
34
|
+
|
35
|
+
#down case the whole thing
|
36
|
+
x.downcase!
|
37
|
+
|
38
|
+
# get rid of any characters at the beginning that aren't a-z
|
39
|
+
while !x.match(/^[a-z]/)
|
40
|
+
x.slice!(0)
|
41
|
+
|
42
|
+
# if we get down to a nil or an empty string raise an exception!
|
43
|
+
raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
|
44
|
+
end
|
45
|
+
|
46
|
+
# let's trim this bad boy down a bit now that we've cleaned it up, somewhat.
|
47
|
+
# we should do this before cleaning up the end character, because it's possible to end up with a
|
48
|
+
# bad char at the end if you trim too late.
|
49
|
+
x = x[0..100] if x.length > 100
|
50
|
+
|
51
|
+
# get rid of any characters at the end that aren't safe
|
52
|
+
while !x.match(/[a-z0-9\?\!\=]$/)
|
53
|
+
x.slice!(x.length - 1)
|
54
|
+
# if we get down to a nil or an empty string raise an exception!
|
55
|
+
raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
|
56
|
+
end
|
57
|
+
|
58
|
+
# if we get down to a nil or an empty string raise an exception!
|
59
|
+
raise NameError.new("#{self} cannot be converted to a valid method name!") if x.nil? || x == ''
|
60
|
+
|
61
|
+
# let's get rid of characters that don't belong in the 'middle' of the method.
|
62
|
+
orig_middle = x[1..(x.length - 2)]
|
63
|
+
n_middle = orig_middle.dup
|
64
|
+
|
65
|
+
['?', '!', "="].each do |c|
|
66
|
+
n_middle.gsub!(c, "_")
|
67
|
+
end
|
68
|
+
|
69
|
+
# the previous gsub can leave us with multiple underscores that need cleaning up.
|
70
|
+
n_middle.squeeze!("_")
|
71
|
+
|
72
|
+
x.gsub!(orig_middle, n_middle)
|
73
|
+
x.gsub!("_=", "=")
|
74
|
+
x
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns a constant of the string.
|
78
|
+
#
|
79
|
+
# Examples:
|
80
|
+
# "User".constantize # => User
|
81
|
+
# "HomeController".constantize # => HomeController
|
82
|
+
# "Mack::Configuration" # => Mack::Configuration
|
83
|
+
def constantize
|
84
|
+
Module.instance_eval("::#{self}")
|
85
|
+
end
|
86
|
+
|
87
|
+
def hexdigest
|
88
|
+
Digest::SHA1.hexdigest(self)
|
89
|
+
end
|
90
|
+
|
91
|
+
def hexdigest!
|
92
|
+
self.replace(self.hexdigest)
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.randomize(length = 10)
|
96
|
+
chars = ("A".."H").to_a + ("J".."N").to_a + ("P".."T").to_a + ("W".."Z").to_a + ("3".."9").to_a
|
97
|
+
newpass = ""
|
98
|
+
1.upto(length) { |i| newpass << chars[rand(chars.size-1)] }
|
99
|
+
return newpass.upcase
|
100
|
+
end
|
101
|
+
|
102
|
+
# Performs URI escaping so that you can construct proper
|
103
|
+
# query strings faster. Use this rather than the cgi.rb
|
104
|
+
# version since it's faster. (Stolen from Camping).
|
105
|
+
def uri_escape
|
106
|
+
self.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
107
|
+
'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
108
|
+
}.tr(' ', '+')
|
109
|
+
end
|
110
|
+
|
111
|
+
# Unescapes a URI escaped string. (Stolen from Camping).
|
112
|
+
def uri_unescape
|
113
|
+
self.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
114
|
+
[$1.delete('%')].pack('H*')
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def truncate(length = 30, truncate_string = "...")
|
119
|
+
if self.nil? then return end
|
120
|
+
l = length - truncate_string.length
|
121
|
+
if $KCODE == "NONE"
|
122
|
+
self.length > length ? self[0...l] + truncate_string : self
|
123
|
+
else
|
124
|
+
chars = self.split(//)
|
125
|
+
chars.length > length ? chars[0...l].join + truncate_string : self
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def truncate!(length = 30, truncate_string = "...")
|
130
|
+
self.replace(self.truncate(length, truncate_string))
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
# require 'digest'
|
135
|
+
# class String
|
136
|
+
#
|
137
|
+
# # Maps to Mack::Utils::Inflector.instance.pluralize
|
138
|
+
# def plural
|
139
|
+
# Mack::Utils::Inflector.instance.pluralize(self)
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# # Maps to Mack::Utils::Inflector.instance.singularize
|
143
|
+
# def singular
|
144
|
+
# Mack::Utils::Inflector.instance.singularize(self)
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
|
148
|
+
#
|
149
|
+
#
|
150
|
+
# def underscore
|
151
|
+
# camel_cased_word = self.dup
|
152
|
+
# camel_cased_word.to_s.gsub(/::/, '/').
|
153
|
+
# gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
154
|
+
# gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
155
|
+
# tr("-", "_").
|
156
|
+
# downcase
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# def starts_with?(x)
|
160
|
+
# self.match(/^#{x}/) ? true : false
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# def ends_with?(x)
|
164
|
+
# self.match(/#{x}$/) ? true : false
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# # Returns "is" or "are" based on the number, i.e. "i=6; There #{isare(i)} #{i} topics here."
|
168
|
+
# def self.pluralize_word(num, vals = ["is", "are"])
|
169
|
+
# return vals[0] if num.to_i==1
|
170
|
+
# return vals[1]
|
171
|
+
# end
|
172
|
+
#
|
173
|
+
# def remove(val)
|
174
|
+
# gsub(val, '')
|
175
|
+
# end
|
176
|
+
#
|
177
|
+
# def remove!(val)
|
178
|
+
# gsub!(val, '')
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
|
182
|
+
#
|
183
|
+
# def truncate(length = 30, truncate_string = "...")
|
184
|
+
# if self.nil? then return end
|
185
|
+
# l = length - truncate_string.length
|
186
|
+
# if $KCODE == "NONE"
|
187
|
+
# self.length > length ? self[0...l] + truncate_string : self
|
188
|
+
# else
|
189
|
+
# chars = self.split(//)
|
190
|
+
# chars.length > length ? chars[0...l].join + truncate_string : self
|
191
|
+
# end
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# def truncate!(length = 30, truncate_string = "...")
|
195
|
+
# self.replace(self.truncate(length, truncate_string))
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# def capitalize_all_words
|
199
|
+
# self.gsub(/\b\w/) {|s| s.upcase}
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# def capitalize_all_words!
|
203
|
+
# self.replace(self.capitalize_all_words)
|
204
|
+
# end
|
205
|
+
#
|
206
|
+
# # keep adding on to this whenever it becomes apparent that unsafe strings
|
207
|
+
# # could get passed through into the database
|
208
|
+
# def sql_safe_str
|
209
|
+
# if !self.nil?
|
210
|
+
# self.gsub(/[\']/, "\'\'")
|
211
|
+
# end
|
212
|
+
# end
|
213
|
+
#
|
214
|
+
# def sql_safe_str!
|
215
|
+
# self.replace(self.sql_safe_str)
|
216
|
+
# end
|
217
|
+
#
|
218
|
+
# end
|
data/lib/mack-facets.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'digest'
|
3
|
+
require 'facets'
|
4
|
+
require 'facets/ruby'
|
5
|
+
require 'facets/style'
|
6
|
+
require 'facets/blank'
|
7
|
+
require 'facets/hash'
|
8
|
+
require 'facets/hash/symbolize_keys'
|
9
|
+
require 'facets/hash/stringify_keys'
|
10
|
+
require 'facets/module'
|
11
|
+
require 'facets/infinity'
|
12
|
+
require 'english/inflect'
|
13
|
+
require 'english/numerals'
|
14
|
+
[:inflector, :inflections, :options_merger].each do |k|
|
15
|
+
path = File.join File.dirname(__FILE__), "utils", "#{k}"
|
16
|
+
#puts "requiring #{path}"
|
17
|
+
require path
|
18
|
+
end
|
19
|
+
|
20
|
+
[:array, :class, :hash, :kernel, :math, :module, :object, :string, :symbol].each do |k|
|
21
|
+
path = File.join File.dirname(__FILE__), "extensions", "#{k}"
|
22
|
+
#puts "requiring #{path}"
|
23
|
+
require path
|
24
|
+
end
|
25
|
+
|
26
|
+
[:numerals, :inflect].each do |k|
|
27
|
+
path = File.join File.dirname(__FILE__), "english_extensions", "#{k}"
|
28
|
+
#puts "requiring #{path}"
|
29
|
+
require path
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "inflector")
|
2
|
+
# Default inflections. This is taken from Jeremy McAnally's great Rails plugin, acts_as_good_speeler. Thanks Jeremy! http://www.jeremymcanally.com/
|
3
|
+
Mack::Utils::Inflector.inflections do |inflect|
|
4
|
+
# inflect.plural(/$/, 's')
|
5
|
+
inflect.plural(/s$/i, 's')
|
6
|
+
inflect.plural(/(bu)s$/i, '\1ses')
|
7
|
+
inflect.plural(/(stimul|hippopotam|octop|vir|syllab|foc|alumn|fung|radi)us$/i, '\1i')
|
8
|
+
inflect.plural(/(ax|test)is$/i, '\1es')
|
9
|
+
inflect.plural(/(alias|status)$/i, '\1es')
|
10
|
+
inflect.plural(/(buffal|tomat|torped)o$/i, '\1oes')
|
11
|
+
inflect.plural(/([dti])um$/i, '\1a')
|
12
|
+
inflect.plural(/sis$/i, 'ses')
|
13
|
+
inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
|
14
|
+
inflect.plural(/(hive)$/i, '\1s')
|
15
|
+
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
|
16
|
+
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
|
17
|
+
inflect.plural(/(matr|append|vert|ind)ix|ex$/i, '\1ices')
|
18
|
+
inflect.plural(/([m|l])ouse$/i, '\1ice')
|
19
|
+
inflect.plural(/^(ox)$/i, '\1en')
|
20
|
+
inflect.plural(/(quiz)$/i, '\1zes')
|
21
|
+
inflect.plural(/(phenomen|criteri)on$/i, '\1a')
|
22
|
+
inflect.plural(/^(?!(.*hu|.*ger|.*sha))(.*)(wom|m)an$/i, '\2\3en')
|
23
|
+
inflect.plural(/(curricul|bacteri|medi)um$/i, '\1a')
|
24
|
+
inflect.plural(/(nebul|formul|vit|vertebr|alg|alumn)a$/i, '\1ae')
|
25
|
+
|
26
|
+
# inflect.singular(/s$/i, '')
|
27
|
+
inflect.singular(/(n)ews$/i, '\1ews')
|
28
|
+
inflect.singular(/([dti])a$/i, '\1um')
|
29
|
+
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
|
30
|
+
inflect.singular(/(^analy|cri|empha)ses$/i, '\1sis')
|
31
|
+
inflect.singular(/([^f])ves$/i, '\1fe')
|
32
|
+
inflect.singular(/(hive)s$/i, '\1')
|
33
|
+
inflect.singular(/(tive)s$/i, '\1')
|
34
|
+
inflect.singular(/(bus)es$/i, '\1')
|
35
|
+
inflect.singular(/(o)es$/i, '\1')
|
36
|
+
inflect.singular(/(shoe)s$/i, '\1')
|
37
|
+
inflect.singular(/(test|ax)es$/i, '\1is')
|
38
|
+
inflect.singular(/(stimul|hippopotam|octop|vir|syllab|foc|alumn|fung|radi)i$/i, '\1us')
|
39
|
+
inflect.singular(/(alias|status)es$/i, '\1')
|
40
|
+
inflect.singular(/^(ox)en$/i, '\1')
|
41
|
+
inflect.singular(/(vert|ind)ices$/i, '\1ex')
|
42
|
+
inflect.singular(/(matr|append)ices$/i, '\1ix')
|
43
|
+
inflect.singular(/(quiz)zes$/i, '\1')
|
44
|
+
inflect.singular(/(phenomen|criteri)a$/i, '\1on')
|
45
|
+
inflect.singular(/(.*)(wo|m)en$/i, '\1\2an')
|
46
|
+
inflect.singular(/(medi|curricul|bacteri)a$/i, '\1um')
|
47
|
+
inflect.singular(/(nebula|formula|vita|vertebra|alga|alumna)e$/i, '\1')
|
48
|
+
inflect.singular(/^(.*)ookies$/, '\1ookie')
|
49
|
+
inflect.singular(/(.*)ss$/, '\1ss')
|
50
|
+
inflect.singular(/(.*)ies$/, '\1y')
|
51
|
+
|
52
|
+
inflect.irregular('person', 'people')
|
53
|
+
inflect.irregular('child', 'children')
|
54
|
+
inflect.irregular('sex', 'sexes')
|
55
|
+
inflect.irregular('move', 'moves')
|
56
|
+
inflect.irregular('tooth', 'teeth')
|
57
|
+
inflect.irregular('die', 'dice')
|
58
|
+
inflect.irregular('talisman', 'talismans')
|
59
|
+
inflect.irregular('penis', 'penises')
|
60
|
+
inflect.irregular('christmas', 'christmases')
|
61
|
+
inflect.irregular('knowledge', 'knowledge')
|
62
|
+
inflect.irregular('quiz', 'quizzes')
|
63
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "english_extensions", 'inflect')
|
3
|
+
module Mack # :nodoc:
|
4
|
+
module Utils # :nodoc:
|
5
|
+
# This class is used to deal with inflection strings. This means taken a string and make it plural, or singular, etc...
|
6
|
+
# Inflection rules can be added very easy, and are checked from the bottom up. This means that the last rule is the first
|
7
|
+
# rule to be matched. The exception to this, kind of, is 'irregular' and 'uncountable' rules. The 'uncountable' rules are
|
8
|
+
# always checked first, then the 'irregular' rules, and finally either the 'singular' or 'plural' rules, depending on what
|
9
|
+
# you're trying to do. Within each of these sets of rules, the last rule in is the first rule matched.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
# Mack::Utils::Inflector.inflections do |inflect|
|
13
|
+
# inflect.plural(/$/, 's')
|
14
|
+
# inflect.plural(/^(ox)$/i, '\1en')
|
15
|
+
# inflect.plural(/(phenomen|criteri)on$/i, '\1a')
|
16
|
+
#
|
17
|
+
# inflect.singular(/s$/i, '')
|
18
|
+
# inflect.singular(/(n)ews$/i, '\1ews')
|
19
|
+
# inflect.singular(/^(.*)ookies$/, '\1ookie')
|
20
|
+
#
|
21
|
+
# inflect.irregular('person', 'people')
|
22
|
+
# inflect.irregular('child', 'children')
|
23
|
+
# end
|
24
|
+
class Inflector
|
25
|
+
include Singleton
|
26
|
+
|
27
|
+
# Adds a plural rule to the system.
|
28
|
+
#
|
29
|
+
# Example:
|
30
|
+
# Mack::Utils::Inflector.inflections do |inflect|
|
31
|
+
# inflect.plural(/$/, 's')
|
32
|
+
# inflect.plural(/^(ox)$/i, '\1en')
|
33
|
+
# inflect.plural(/(phenomen|criteri)on$/i, '\1a')
|
34
|
+
# end
|
35
|
+
def plural(rule, replacement)
|
36
|
+
English::Inflect.plural_rule(rule, replacement)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Adds a singular rule to the system.
|
40
|
+
#
|
41
|
+
# Example:
|
42
|
+
# Mack::Utils::Inflector.inflections do |inflect|
|
43
|
+
# inflect.singular(/s$/i, '')
|
44
|
+
# inflect.singular(/(n)ews$/i, '\1ews')
|
45
|
+
# inflect.singular(/^(.*)ookies$/, '\1ookie')
|
46
|
+
# end
|
47
|
+
def singular(rule, replacement)
|
48
|
+
English::Inflect.singular_rule(rule, replacement)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Adds a irregular rule to the system.
|
52
|
+
#
|
53
|
+
# Example:
|
54
|
+
# Mack::Utils::Inflector.inflections do |inflect|
|
55
|
+
# inflect.irregular('person', 'people')
|
56
|
+
# inflect.irregular('child', 'children')
|
57
|
+
# end
|
58
|
+
def irregular(rule, replacement)
|
59
|
+
English::Inflect.rule(rule, replacement)
|
60
|
+
English::Inflect.word(rule, replacement)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the singular version of the word, if possible.
|
64
|
+
#
|
65
|
+
# Examples:
|
66
|
+
# Mack::Utils::Inflector.instance.singularize("armies") # => "army"
|
67
|
+
# Mack::Utils::Inflector.instance.singularize("people") # => "person"
|
68
|
+
# Mack::Utils::Inflector.instance.singularize("boats") # => "boat"
|
69
|
+
def singularize(word)
|
70
|
+
English::Inflect.singular(word)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the singular version of the word, if possible.
|
74
|
+
#
|
75
|
+
# Examples:
|
76
|
+
# Mack::Utils::Inflector.instance.pluralize("army") # => "armies"
|
77
|
+
# Mack::Utils::Inflector.instance.pluralize("person") # => "people"
|
78
|
+
# Mack::Utils::Inflector.instance.pluralize("boat") # => "boats"
|
79
|
+
def pluralize(word)
|
80
|
+
English::Inflect.plural(word)
|
81
|
+
end
|
82
|
+
|
83
|
+
public
|
84
|
+
class << self
|
85
|
+
|
86
|
+
# Yields up Mack::Utils::Inflector.instance
|
87
|
+
def inflections
|
88
|
+
if block_given?
|
89
|
+
yield Mack::Utils::Inflector.instance
|
90
|
+
else
|
91
|
+
Mack::Utils::Inflector.instance
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end # Inflection
|
98
|
+
end # Utils
|
99
|
+
end # Mack
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Mack
|
2
|
+
module Utils
|
3
|
+
class OptionMerger #:nodoc:
|
4
|
+
instance_methods.each do |method|
|
5
|
+
undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(context, options)
|
9
|
+
@context, @options = context, options
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def method_missing(method, *arguments, &block)
|
14
|
+
merge_argument_options! arguments
|
15
|
+
@context.send(method, *arguments, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def merge_argument_options!(arguments)
|
19
|
+
arguments << if arguments.last.respond_to? :to_hash
|
20
|
+
@options.merge(arguments.pop)
|
21
|
+
else
|
22
|
+
@options.dup
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end # OptionMerger
|
26
|
+
end # Utils
|
27
|
+
end # Mack
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mack-facets
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- markbates
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-16 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: facets
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - "="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.4.1
|
23
|
+
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: english
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - "="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 0.2.0
|
32
|
+
version:
|
33
|
+
description: "mack-facets was developed by: markbates"
|
34
|
+
email: mark@mackframework.com
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README
|
41
|
+
files:
|
42
|
+
- lib/english_extensions/inflect.rb
|
43
|
+
- lib/english_extensions/numerals.rb
|
44
|
+
- lib/extensions/array.rb
|
45
|
+
- lib/extensions/class.rb
|
46
|
+
- lib/extensions/hash.rb
|
47
|
+
- lib/extensions/kernel.rb
|
48
|
+
- lib/extensions/math.rb
|
49
|
+
- lib/extensions/module.rb
|
50
|
+
- lib/extensions/object.rb
|
51
|
+
- lib/extensions/string.rb
|
52
|
+
- lib/extensions/symbol.rb
|
53
|
+
- lib/mack-facets.rb
|
54
|
+
- lib/utils/inflections.rb
|
55
|
+
- lib/utils/inflector.rb
|
56
|
+
- lib/utils/options_merger.rb
|
57
|
+
- README
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://www.mackframework.com
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 1.8.6
|
71
|
+
version:
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project: magrathea
|
81
|
+
rubygems_version: 1.1.1
|
82
|
+
signing_key:
|
83
|
+
specification_version: 2
|
84
|
+
summary: Ruby language extensions for Mack
|
85
|
+
test_files: []
|
86
|
+
|