garcun 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitattributes +17 -0
- data/.gitignore +197 -0
- data/.rspec +2 -0
- data/Gemfile +22 -0
- data/LICENSE +201 -0
- data/README.md +521 -0
- data/Rakefile +47 -0
- data/garcun.gemspec +83 -0
- data/lib/garcon.rb +290 -0
- data/lib/garcon/chef/chef_helpers.rb +343 -0
- data/lib/garcon/chef/coerce/coercer.rb +134 -0
- data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
- data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
- data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
- data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
- data/lib/garcon/chef/handler/devreporter.rb +127 -0
- data/lib/garcon/chef/log.rb +64 -0
- data/lib/garcon/chef/node.rb +100 -0
- data/lib/garcon/chef/provider/civilize.rb +209 -0
- data/lib/garcon/chef/provider/development.rb +159 -0
- data/lib/garcon/chef/provider/download.rb +420 -0
- data/lib/garcon/chef/provider/house_keeping.rb +265 -0
- data/lib/garcon/chef/provider/node_cache.rb +31 -0
- data/lib/garcon/chef/provider/partial.rb +183 -0
- data/lib/garcon/chef/provider/recovery.rb +80 -0
- data/lib/garcon/chef/provider/zip_file.rb +271 -0
- data/lib/garcon/chef/resource/attribute.rb +52 -0
- data/lib/garcon/chef/resource/base_dsl.rb +174 -0
- data/lib/garcon/chef/resource/blender.rb +140 -0
- data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
- data/lib/garcon/chef/resource/resource_name.rb +109 -0
- data/lib/garcon/chef/secret_bag.rb +204 -0
- data/lib/garcon/chef/validations.rb +76 -0
- data/lib/garcon/chef_inclusions.rb +151 -0
- data/lib/garcon/configuration.rb +138 -0
- data/lib/garcon/core_ext.rb +39 -0
- data/lib/garcon/core_ext/array.rb +27 -0
- data/lib/garcon/core_ext/binding.rb +64 -0
- data/lib/garcon/core_ext/boolean.rb +66 -0
- data/lib/garcon/core_ext/duration.rb +271 -0
- data/lib/garcon/core_ext/enumerable.rb +34 -0
- data/lib/garcon/core_ext/file.rb +127 -0
- data/lib/garcon/core_ext/filetest.rb +62 -0
- data/lib/garcon/core_ext/hash.rb +279 -0
- data/lib/garcon/core_ext/kernel.rb +159 -0
- data/lib/garcon/core_ext/lazy.rb +222 -0
- data/lib/garcon/core_ext/method_access.rb +243 -0
- data/lib/garcon/core_ext/module.rb +92 -0
- data/lib/garcon/core_ext/nil.rb +53 -0
- data/lib/garcon/core_ext/numeric.rb +44 -0
- data/lib/garcon/core_ext/object.rb +342 -0
- data/lib/garcon/core_ext/pathname.rb +152 -0
- data/lib/garcon/core_ext/process.rb +41 -0
- data/lib/garcon/core_ext/random.rb +497 -0
- data/lib/garcon/core_ext/string.rb +312 -0
- data/lib/garcon/core_ext/struct.rb +49 -0
- data/lib/garcon/core_ext/symbol.rb +170 -0
- data/lib/garcon/core_ext/time.rb +234 -0
- data/lib/garcon/exceptions.rb +101 -0
- data/lib/garcon/inflections.rb +237 -0
- data/lib/garcon/inflections/defaults.rb +79 -0
- data/lib/garcon/inflections/inflections.rb +182 -0
- data/lib/garcon/inflections/rules_collection.rb +37 -0
- data/lib/garcon/secret.rb +271 -0
- data/lib/garcon/stash/format.rb +114 -0
- data/lib/garcon/stash/journal.rb +226 -0
- data/lib/garcon/stash/queue.rb +83 -0
- data/lib/garcon/stash/serializer.rb +86 -0
- data/lib/garcon/stash/store.rb +435 -0
- data/lib/garcon/task.rb +31 -0
- data/lib/garcon/task/atomic.rb +151 -0
- data/lib/garcon/task/atomic_boolean.rb +127 -0
- data/lib/garcon/task/condition.rb +99 -0
- data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
- data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
- data/lib/garcon/task/count_down_latch.rb +92 -0
- data/lib/garcon/task/delay.rb +196 -0
- data/lib/garcon/task/dereferenceable.rb +144 -0
- data/lib/garcon/task/event.rb +119 -0
- data/lib/garcon/task/executor.rb +275 -0
- data/lib/garcon/task/executor_options.rb +59 -0
- data/lib/garcon/task/future.rb +107 -0
- data/lib/garcon/task/immediate_executor.rb +84 -0
- data/lib/garcon/task/ivar.rb +171 -0
- data/lib/garcon/task/lazy_reference.rb +74 -0
- data/lib/garcon/task/monotonic_time.rb +69 -0
- data/lib/garcon/task/obligation.rb +256 -0
- data/lib/garcon/task/observable.rb +101 -0
- data/lib/garcon/task/priority_queue.rb +234 -0
- data/lib/garcon/task/processor_count.rb +128 -0
- data/lib/garcon/task/read_write_lock.rb +304 -0
- data/lib/garcon/task/safe_task_executor.rb +58 -0
- data/lib/garcon/task/single_thread_executor.rb +97 -0
- data/lib/garcon/task/thread_pool/cached.rb +71 -0
- data/lib/garcon/task/thread_pool/executor.rb +294 -0
- data/lib/garcon/task/thread_pool/fixed.rb +61 -0
- data/lib/garcon/task/thread_pool/worker.rb +90 -0
- data/lib/garcon/task/timer.rb +44 -0
- data/lib/garcon/task/timer_set.rb +194 -0
- data/lib/garcon/task/timer_task.rb +377 -0
- data/lib/garcon/task/waitable_list.rb +58 -0
- data/lib/garcon/utility/ansi.rb +199 -0
- data/lib/garcon/utility/at_random.rb +77 -0
- data/lib/garcon/utility/crypto.rb +292 -0
- data/lib/garcon/utility/equalizer.rb +146 -0
- data/lib/garcon/utility/faker/extensions/array.rb +22 -0
- data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
- data/lib/garcon/utility/faker/faker.rb +164 -0
- data/lib/garcon/utility/faker/faker/company.rb +17 -0
- data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
- data/lib/garcon/utility/faker/faker/version.rb +3 -0
- data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
- data/lib/garcon/utility/faker/locales/en.yml +21 -0
- data/lib/garcon/utility/file_helper.rb +170 -0
- data/lib/garcon/utility/hookers.rb +178 -0
- data/lib/garcon/utility/interpolation.rb +90 -0
- data/lib/garcon/utility/memstash.rb +364 -0
- data/lib/garcon/utility/misc.rb +54 -0
- data/lib/garcon/utility/msg_from_god.rb +62 -0
- data/lib/garcon/utility/retry.rb +238 -0
- data/lib/garcon/utility/timeout.rb +58 -0
- data/lib/garcon/utility/uber/builder.rb +91 -0
- data/lib/garcon/utility/uber/callable.rb +7 -0
- data/lib/garcon/utility/uber/delegates.rb +13 -0
- data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
- data/lib/garcon/utility/uber/options.rb +101 -0
- data/lib/garcon/utility/uber/uber_version.rb +3 -0
- data/lib/garcon/utility/uber/version.rb +33 -0
- data/lib/garcon/utility/url_helper.rb +100 -0
- data/lib/garcon/utils.rb +29 -0
- data/lib/garcon/version.rb +62 -0
- data/lib/garcun.rb +24 -0
- metadata +680 -0
@@ -0,0 +1,234 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
4
|
+
# License: Apache License, Version 2.0
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
# Add #elapse
|
21
|
+
class Time
|
22
|
+
# Tracks the elapse time of a code block.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# e = Time.elapse { sleep 1 }
|
26
|
+
# e.assert > 1
|
27
|
+
#
|
28
|
+
def self.elapse
|
29
|
+
raise "you need to pass a block" unless block_given?
|
30
|
+
t0 = now.to_f
|
31
|
+
yield
|
32
|
+
now.to_f - t0
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return a float of time since linux epoch
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# Time.time -> 1295953427.0005338
|
39
|
+
#
|
40
|
+
# @return [Float]
|
41
|
+
def self.time
|
42
|
+
now.to_f
|
43
|
+
end
|
44
|
+
|
45
|
+
unless const_defined?('FORMAT')
|
46
|
+
FORMAT = {
|
47
|
+
utc: '%Y-%m-%d %H:%M:%S', # => 2015-04-19 14:03:59
|
48
|
+
utcT: '%Y-%m-%dT%H:%M:%S', # => 2015-04-19T14:03:59
|
49
|
+
db: '%Y-%m-%d %H:%M:%S', # => 2015-04-19 14:03:59
|
50
|
+
database: '%Y-%m-%d %H:%M:%S', # => 2015-04-19 14:03:59
|
51
|
+
number: '%Y%m%d%H%M%S', # => 20150419140359
|
52
|
+
short: '%d %b %H:%M', # => 19 Apr 14:
|
53
|
+
time: '%H:%M', # => 14:03
|
54
|
+
long: '%B %d, %Y %H:%M', # => April 19, 2015 14:03
|
55
|
+
day1st: '%d-%m-%Y %H:%M', # => 19-04-2015 14:03
|
56
|
+
dmYHM: '%d-%m-%Y %H:%M', # => 19-04-2015 14:03
|
57
|
+
rfc822: '%a, %d %b %Y %H:%M:%S %z', # => Sun, 19 Apr 2015 14:03:59 -0700
|
58
|
+
ruby18: '%a %b %d %H:%M:%S %z %Y', # => Sun Apr 19 14:03:59 -0700 2015
|
59
|
+
nil => '%Y-%m-%d %H:%M:%S %z' # => 2015-04-19 14:03:59 -0700
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
# Produce time stamp for Time.now. See #stamp.
|
64
|
+
#
|
65
|
+
def self.stamp(*args)
|
66
|
+
now.stamp(*args)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Create a time stamp.
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# t = Time.at(10000)
|
73
|
+
# t.stamp(:short) # => "31 Dec 21:46"
|
74
|
+
#
|
75
|
+
# Supported formats come from the Time::FORMAT constant.
|
76
|
+
#
|
77
|
+
def stamp(format = nil)
|
78
|
+
unless String === format
|
79
|
+
format = FORMAT[format]
|
80
|
+
end
|
81
|
+
strftime(format).strip
|
82
|
+
end
|
83
|
+
|
84
|
+
unless method_defined?(:dst_adjustment)
|
85
|
+
# Adjust DST
|
86
|
+
#
|
87
|
+
def dst_adjustment(time)
|
88
|
+
self_dst = self.dst? ? 1 : 0
|
89
|
+
time_dst = time.dst? ? 1 : 0
|
90
|
+
seconds = (self - time).abs
|
91
|
+
if (seconds >= 86400 && self_dst != time_dst)
|
92
|
+
time + ((self_dst - time_dst) * 60 * 60)
|
93
|
+
else
|
94
|
+
time
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Like change but does not reset earlier times.
|
100
|
+
#
|
101
|
+
def set(options)
|
102
|
+
opts={}
|
103
|
+
options.each_pair do |k,v|
|
104
|
+
k = :min if k.to_s =~ /^min/
|
105
|
+
k = :sec if k.to_s =~ /^sec/
|
106
|
+
opts[k] = v.to_i
|
107
|
+
end
|
108
|
+
self.class.send(
|
109
|
+
self.utc? ? :utc : :local,
|
110
|
+
opts[:year] || self.year,
|
111
|
+
opts[:month] || self.month,
|
112
|
+
opts[:day] || self.day,
|
113
|
+
opts[:hour] || self.hour,
|
114
|
+
opts[:min] || self.min,
|
115
|
+
opts[:sec] || self.sec,
|
116
|
+
opts[:usec] || self.usec
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns a new Time representing the time shifted by the time-units given.
|
121
|
+
# Positive number shift the time forward, negative number shift the time
|
122
|
+
# backward.
|
123
|
+
#
|
124
|
+
# @example
|
125
|
+
# t = Time.utc(2010,10,10,0,0,0)
|
126
|
+
# t.shift( 4, :days) # => Time.utc(2010,10,14,0,0,0)
|
127
|
+
# t.shift(-4, :days) # => Time.utc(2010,10,6,0,0,0)
|
128
|
+
#
|
129
|
+
# More than one unit of time can be given.
|
130
|
+
# t.shift(4, :days, 3, :hours) # => Time.utc(2010,10,14,3,0,0)
|
131
|
+
#
|
132
|
+
# The #shift method can also take a hash.
|
133
|
+
# t.shift(:days=>4, :hours=>3) # => Time.utc(2010,10,14,3,0,0)
|
134
|
+
#
|
135
|
+
def shift(*time_units)
|
136
|
+
time_hash = Hash===time_units.last ? time_units.pop : {}
|
137
|
+
time_units = time_units.flatten
|
138
|
+
time_units << :seconds if time_units.size % 2 == 1
|
139
|
+
time_hash.each{ |units, number| time_units << number; time_units << units }
|
140
|
+
|
141
|
+
time = self
|
142
|
+
time_units.each_slice(2) do |number, units|
|
143
|
+
#next time = time.ago(-number, units) if number < 0
|
144
|
+
time = (
|
145
|
+
case units.to_s.downcase.to_sym
|
146
|
+
when :years, :year
|
147
|
+
time.set( :year=>(year + number) )
|
148
|
+
when :months, :month
|
149
|
+
if number > 0
|
150
|
+
new_month = ((month + number - 1) % 12) + 1
|
151
|
+
y = (number / 12) + (new_month < month ? 1 : 0)
|
152
|
+
time.set(:year => (year + y), :month => new_month)
|
153
|
+
else
|
154
|
+
number = -number
|
155
|
+
new_month = ((month - number - 1) % 12) + 1
|
156
|
+
y = (number / 12) + (new_month > month ? 1 : 0)
|
157
|
+
time.set(:year => (year - y), :month => new_month)
|
158
|
+
end
|
159
|
+
when :weeks, :week
|
160
|
+
time + (number * 604800)
|
161
|
+
when :days, :day
|
162
|
+
time + (number * 86400)
|
163
|
+
when :hours, :hour
|
164
|
+
time + (number * 3600)
|
165
|
+
when :minutes, :minute, :mins, :min
|
166
|
+
time + (number * 60)
|
167
|
+
when :seconds, :second, :secs, :sec, nil
|
168
|
+
time + number
|
169
|
+
else
|
170
|
+
raise ArgumentError, "unrecognized time units -- #{units}"
|
171
|
+
end
|
172
|
+
)
|
173
|
+
end
|
174
|
+
dst_adjustment(time)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Alias for #shift.
|
178
|
+
alias_method :in, :shift
|
179
|
+
|
180
|
+
# Alias for #shift.
|
181
|
+
alias_method :hence, :shift unless method_defined?(:hence)
|
182
|
+
|
183
|
+
# Returns a new Time representing the time a number of time-units ago.
|
184
|
+
# This is just like #shift, but reverses the direction.
|
185
|
+
#
|
186
|
+
# @example
|
187
|
+
# t = Time.utc(2010,10,10,0,0,0)
|
188
|
+
# t.less(4, :days) # => Time.utc(2010,10,6,0,0,0)
|
189
|
+
#
|
190
|
+
def less(*time_units)
|
191
|
+
time_hash = Hash===time_units.last ? time_units.pop : {}
|
192
|
+
time_units = time_units.flatten
|
193
|
+
|
194
|
+
time_units << :seconds if time_units.size % 2 == 1
|
195
|
+
|
196
|
+
time_hash.each{ |units, number| time_units << number; time_units << units }
|
197
|
+
|
198
|
+
neg_times = []
|
199
|
+
time_units.each_slice(2){ |number, units| neg_times << -number; neg_times << units }
|
200
|
+
|
201
|
+
shift(*neg_times)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Alias for #less
|
205
|
+
alias_method :ago, :less unless method_defined?(:ago)
|
206
|
+
end
|
207
|
+
|
208
|
+
class Numeric
|
209
|
+
# Reports the approximate distance in time between two Time, Date or DateTime
|
210
|
+
# objects or integers as seconds.
|
211
|
+
#
|
212
|
+
# @example
|
213
|
+
# 1.time_humanize(true) -> 1 seconds
|
214
|
+
# 36561906.time_humanize -> 1 years 2 months 3 days 4 hours 5 minutes
|
215
|
+
#
|
216
|
+
def time_humanize(include_seconds = false)
|
217
|
+
deta = self
|
218
|
+
deta, seconds = deta.divmod(60)
|
219
|
+
deta, minutes = deta.divmod(60)
|
220
|
+
deta, hours = deta.divmod(24)
|
221
|
+
deta, days = deta.divmod(30)
|
222
|
+
years, months = deta.divmod(12)
|
223
|
+
|
224
|
+
ret = ''
|
225
|
+
ret << "#{years} years " unless years == 0
|
226
|
+
ret << "#{months} months " unless months == 0
|
227
|
+
ret << "#{days} days " unless days == 0
|
228
|
+
ret << "#{hours} hours " unless hours == 0
|
229
|
+
ret << "#{minutes} minutes " unless minutes == 0
|
230
|
+
ret << "#{seconds} seconds" if include_seconds
|
231
|
+
|
232
|
+
ret.rstrip
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
4
|
+
# License: Apache License, Version 2.0
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
# Include hooks to extend Resource with class and instance methods.
|
21
|
+
#
|
22
|
+
module Garcon
|
23
|
+
# When foo and bar collide, exceptions happen.
|
24
|
+
#
|
25
|
+
module Exceptions
|
26
|
+
|
27
|
+
class UnsupportedPlatform < RuntimeError
|
28
|
+
def initialize(platform)
|
29
|
+
super "This functionality is not supported on platform #{platform}."
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class ValidationError < RuntimeError
|
34
|
+
attr_accessor :value, :type
|
35
|
+
|
36
|
+
def initialize(value, type = nil)
|
37
|
+
@value, @type = value, type
|
38
|
+
super(build_message)
|
39
|
+
super(detail)
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_message
|
43
|
+
if type?
|
44
|
+
"#{value} is not a valid #{type}"
|
45
|
+
else
|
46
|
+
"Failed to validate #{value.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def type?
|
51
|
+
type.nil? ? false : true
|
52
|
+
end
|
53
|
+
|
54
|
+
# Pretty string output of exception/error object useful for helpful
|
55
|
+
# debug messages.
|
56
|
+
#
|
57
|
+
def detail
|
58
|
+
if backtrace
|
59
|
+
%{#{self.class.name}: #{message}\n #{backtrace.join("\n ")}\n LOGGED FROM: #{caller[0]}}
|
60
|
+
else
|
61
|
+
%{#{self.class.name}: #{message}\n LOGGED FROM: #{caller[0]}}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Raised when errors occur during configuration.
|
67
|
+
ConfigurationError = Class.new(StandardError)
|
68
|
+
|
69
|
+
# Raised when an object's methods are called when it has not been
|
70
|
+
# properly initialized.
|
71
|
+
InitializationError = Class.new(StandardError)
|
72
|
+
|
73
|
+
# If the maximum number of ReadWriteLock readers or writers is exceeded.
|
74
|
+
ResourceLimitError = Class.new(StandardError)
|
75
|
+
|
76
|
+
# Raised by an `Executor` when it is unable to process a given task,
|
77
|
+
# possibly because of a reject policy or other internal error.
|
78
|
+
RejectedExecutionError = Class.new(StandardError)
|
79
|
+
|
80
|
+
# Raised when an operation times out.
|
81
|
+
TimeoutError = Class.new(StandardError)
|
82
|
+
PollingError = Class.new(StandardError)
|
83
|
+
|
84
|
+
# Raised when node[:garcon][:databag_type] is not valid.
|
85
|
+
InvalidDataBagTypeError = Class.new(RuntimeError)
|
86
|
+
|
87
|
+
# Raised when cipher direction is invalid.
|
88
|
+
InvalidCipherError = Class.new(RuntimeError)
|
89
|
+
|
90
|
+
# Raised when no encryption key password is specified.
|
91
|
+
MissingEncryptionPasswordError = Class.new(RuntimeError)
|
92
|
+
|
93
|
+
ResourceNotFoundError = Class.new(RuntimeError)
|
94
|
+
InvalidStateError = Class.new(RuntimeError)
|
95
|
+
InvalidTransitionError = Class.new(RuntimeError)
|
96
|
+
InvalidCallbackError = Class.new(RuntimeError)
|
97
|
+
TransitionFailedError = Class.new(RuntimeError)
|
98
|
+
TransitionConflictError = Class.new(RuntimeError)
|
99
|
+
GuardFailedError = Class.new(RuntimeError)
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
4
|
+
# License: Apache License, Version 2.0
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'set'
|
21
|
+
|
22
|
+
module Garcon
|
23
|
+
# The Inflections transforms words from singular to plural, class names to
|
24
|
+
# table names, modularized class names to ones without, and class names to
|
25
|
+
# foreign keys. The default inflections for pluralization, singularization,
|
26
|
+
# and uncountable words are kept in inflections.rb.
|
27
|
+
#
|
28
|
+
module Inflections
|
29
|
+
# Convert input to UpperCamelCase. Will also convert '/' to '::' which is
|
30
|
+
# useful for converting paths to namespaces.
|
31
|
+
#
|
32
|
+
# @param [String] input
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
#
|
36
|
+
def self.camelize(input)
|
37
|
+
input.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:\A|_)(.)/) {$1.upcase}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Convert input to underscored, lowercase string. Changes '::' to '/' to
|
41
|
+
# convert namespaces to paths.
|
42
|
+
#
|
43
|
+
# @param [String] input
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
#
|
47
|
+
def self.underscore(input)
|
48
|
+
word = input.gsub(/::/, '/')
|
49
|
+
underscorize(word)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Convert input underscores to dashes.
|
53
|
+
#
|
54
|
+
# @param [String] input
|
55
|
+
#
|
56
|
+
# @return [String]
|
57
|
+
#
|
58
|
+
def self.dasherize(input)
|
59
|
+
input.tr('_', '-')
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return unscoped constant name.
|
63
|
+
#
|
64
|
+
# @param [String] input
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
#
|
68
|
+
def self.demodulize(input)
|
69
|
+
input.split('::').last
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates a foreign key name
|
73
|
+
#
|
74
|
+
# @param [String] input
|
75
|
+
#
|
76
|
+
# @return [String]
|
77
|
+
#
|
78
|
+
def self.foreign_key(input)
|
79
|
+
"#{underscorize(demodulize(input))}_id"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Find a constant with the name specified in the argument string. The name
|
83
|
+
# is assumed to be the one of a top-level constant, constant scope of
|
84
|
+
# caller is igored.
|
85
|
+
#
|
86
|
+
# @param [String] input
|
87
|
+
#
|
88
|
+
# @return [Class, Module]
|
89
|
+
#
|
90
|
+
def self.constantize(input)
|
91
|
+
names = input.split('::')
|
92
|
+
names.shift if names.first.empty?
|
93
|
+
|
94
|
+
names.inject(Object) do |constant, name|
|
95
|
+
if constant.const_defined?(name)
|
96
|
+
constant.const_get(name)
|
97
|
+
else
|
98
|
+
constant.const_missing(name)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
ORDINALIZE_TH = (4..16).to_set.freeze
|
104
|
+
|
105
|
+
# Convert a number into an ordinal string.
|
106
|
+
#
|
107
|
+
# @param [Fixnum] number
|
108
|
+
#
|
109
|
+
# @return [String]
|
110
|
+
#
|
111
|
+
def self.ordinalize(number)
|
112
|
+
abs_value = number.abs
|
113
|
+
|
114
|
+
if ORDINALIZE_TH.include?(abs_value % 100)
|
115
|
+
"#{number}th"
|
116
|
+
else
|
117
|
+
case abs_value % 10
|
118
|
+
when 1; "#{number}st"
|
119
|
+
when 2; "#{number}nd"
|
120
|
+
when 3; "#{number}rd"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Convert input word string to plural
|
126
|
+
#
|
127
|
+
# @param [String] word
|
128
|
+
#
|
129
|
+
# @return [String]
|
130
|
+
#
|
131
|
+
def self.pluralize(word)
|
132
|
+
return word if uncountable?(word)
|
133
|
+
inflections.plurals.apply_to(word)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Convert word to singular
|
137
|
+
#
|
138
|
+
# @param [String] word
|
139
|
+
#
|
140
|
+
# @return [String]
|
141
|
+
#
|
142
|
+
def self.singularize(word)
|
143
|
+
return word if uncountable?(word)
|
144
|
+
inflections.singulars.apply_to(word)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Humanize string.
|
148
|
+
#
|
149
|
+
# @param [String] input
|
150
|
+
#
|
151
|
+
# @return [String]
|
152
|
+
#
|
153
|
+
def self.humanize(input)
|
154
|
+
result = inflections.humans.apply_to(input)
|
155
|
+
result.gsub!(/_id\z/, "")
|
156
|
+
result.tr!('_', " ")
|
157
|
+
result.capitalize!
|
158
|
+
result
|
159
|
+
end
|
160
|
+
|
161
|
+
# Tabelize input string.
|
162
|
+
#
|
163
|
+
# @param [String] input
|
164
|
+
#
|
165
|
+
# @return [String]
|
166
|
+
#
|
167
|
+
def self.tableize(input)
|
168
|
+
pluralize(underscore(input).gsub('/', '_'))
|
169
|
+
end
|
170
|
+
|
171
|
+
# Create a class name from a plural table name like Rails does for table
|
172
|
+
# names to models.
|
173
|
+
#
|
174
|
+
# @param [String] input
|
175
|
+
#
|
176
|
+
# @return [String]
|
177
|
+
#
|
178
|
+
def self.classify(table_name)
|
179
|
+
camelize(singularize(table_name.sub(/.*\./, '')))
|
180
|
+
end
|
181
|
+
|
182
|
+
# Create a snake case string with an optional namespace prepended.
|
183
|
+
#
|
184
|
+
# @param [String] input
|
185
|
+
#
|
186
|
+
# @param [String] namespace
|
187
|
+
#
|
188
|
+
# @return [String]
|
189
|
+
#
|
190
|
+
def self.snakeify(input, namespace = nil)
|
191
|
+
input = input.dup
|
192
|
+
input.sub!(/^#{namespace}(\:\:)?/, '') if namespace
|
193
|
+
input.gsub!(/[A-Z]/) {|s| "_" + s}
|
194
|
+
input.downcase!
|
195
|
+
input.sub!(/^\_/, "")
|
196
|
+
input
|
197
|
+
end
|
198
|
+
|
199
|
+
# Test if word is uncountable.
|
200
|
+
#
|
201
|
+
# @param [String] word
|
202
|
+
#
|
203
|
+
# @return [Boolean] true, if word is uncountable
|
204
|
+
#
|
205
|
+
def self.uncountable?(word)
|
206
|
+
word.empty? || inflections.uncountables.include?(word.downcase)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Convert input to underscored, lowercase string
|
210
|
+
#
|
211
|
+
# @param [String] input
|
212
|
+
#
|
213
|
+
# @return [String]
|
214
|
+
#
|
215
|
+
def self.underscorize(word)
|
216
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
217
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
218
|
+
word.tr!('-', '_')
|
219
|
+
word.downcase!
|
220
|
+
word
|
221
|
+
end
|
222
|
+
private_class_method :underscorize
|
223
|
+
|
224
|
+
# Yields a singleton instance of Garcon::Inflections.
|
225
|
+
#
|
226
|
+
# @return [Garcon::Inflections]
|
227
|
+
#
|
228
|
+
def self.inflections
|
229
|
+
instance = Inflections.instance
|
230
|
+
block_given? ? yield(instance) : instance
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
require_relative 'inflections/rules_collection'
|
236
|
+
require_relative 'inflections/inflections'
|
237
|
+
require_relative 'inflections/defaults'
|