garcun 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +17 -0
  3. data/.gitignore +197 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +22 -0
  6. data/LICENSE +201 -0
  7. data/README.md +521 -0
  8. data/Rakefile +47 -0
  9. data/garcun.gemspec +83 -0
  10. data/lib/garcon.rb +290 -0
  11. data/lib/garcon/chef/chef_helpers.rb +343 -0
  12. data/lib/garcon/chef/coerce/coercer.rb +134 -0
  13. data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
  14. data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
  15. data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
  16. data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
  17. data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
  18. data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
  19. data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
  20. data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
  21. data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
  22. data/lib/garcon/chef/handler/devreporter.rb +127 -0
  23. data/lib/garcon/chef/log.rb +64 -0
  24. data/lib/garcon/chef/node.rb +100 -0
  25. data/lib/garcon/chef/provider/civilize.rb +209 -0
  26. data/lib/garcon/chef/provider/development.rb +159 -0
  27. data/lib/garcon/chef/provider/download.rb +420 -0
  28. data/lib/garcon/chef/provider/house_keeping.rb +265 -0
  29. data/lib/garcon/chef/provider/node_cache.rb +31 -0
  30. data/lib/garcon/chef/provider/partial.rb +183 -0
  31. data/lib/garcon/chef/provider/recovery.rb +80 -0
  32. data/lib/garcon/chef/provider/zip_file.rb +271 -0
  33. data/lib/garcon/chef/resource/attribute.rb +52 -0
  34. data/lib/garcon/chef/resource/base_dsl.rb +174 -0
  35. data/lib/garcon/chef/resource/blender.rb +140 -0
  36. data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
  37. data/lib/garcon/chef/resource/resource_name.rb +109 -0
  38. data/lib/garcon/chef/secret_bag.rb +204 -0
  39. data/lib/garcon/chef/validations.rb +76 -0
  40. data/lib/garcon/chef_inclusions.rb +151 -0
  41. data/lib/garcon/configuration.rb +138 -0
  42. data/lib/garcon/core_ext.rb +39 -0
  43. data/lib/garcon/core_ext/array.rb +27 -0
  44. data/lib/garcon/core_ext/binding.rb +64 -0
  45. data/lib/garcon/core_ext/boolean.rb +66 -0
  46. data/lib/garcon/core_ext/duration.rb +271 -0
  47. data/lib/garcon/core_ext/enumerable.rb +34 -0
  48. data/lib/garcon/core_ext/file.rb +127 -0
  49. data/lib/garcon/core_ext/filetest.rb +62 -0
  50. data/lib/garcon/core_ext/hash.rb +279 -0
  51. data/lib/garcon/core_ext/kernel.rb +159 -0
  52. data/lib/garcon/core_ext/lazy.rb +222 -0
  53. data/lib/garcon/core_ext/method_access.rb +243 -0
  54. data/lib/garcon/core_ext/module.rb +92 -0
  55. data/lib/garcon/core_ext/nil.rb +53 -0
  56. data/lib/garcon/core_ext/numeric.rb +44 -0
  57. data/lib/garcon/core_ext/object.rb +342 -0
  58. data/lib/garcon/core_ext/pathname.rb +152 -0
  59. data/lib/garcon/core_ext/process.rb +41 -0
  60. data/lib/garcon/core_ext/random.rb +497 -0
  61. data/lib/garcon/core_ext/string.rb +312 -0
  62. data/lib/garcon/core_ext/struct.rb +49 -0
  63. data/lib/garcon/core_ext/symbol.rb +170 -0
  64. data/lib/garcon/core_ext/time.rb +234 -0
  65. data/lib/garcon/exceptions.rb +101 -0
  66. data/lib/garcon/inflections.rb +237 -0
  67. data/lib/garcon/inflections/defaults.rb +79 -0
  68. data/lib/garcon/inflections/inflections.rb +182 -0
  69. data/lib/garcon/inflections/rules_collection.rb +37 -0
  70. data/lib/garcon/secret.rb +271 -0
  71. data/lib/garcon/stash/format.rb +114 -0
  72. data/lib/garcon/stash/journal.rb +226 -0
  73. data/lib/garcon/stash/queue.rb +83 -0
  74. data/lib/garcon/stash/serializer.rb +86 -0
  75. data/lib/garcon/stash/store.rb +435 -0
  76. data/lib/garcon/task.rb +31 -0
  77. data/lib/garcon/task/atomic.rb +151 -0
  78. data/lib/garcon/task/atomic_boolean.rb +127 -0
  79. data/lib/garcon/task/condition.rb +99 -0
  80. data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
  81. data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
  82. data/lib/garcon/task/count_down_latch.rb +92 -0
  83. data/lib/garcon/task/delay.rb +196 -0
  84. data/lib/garcon/task/dereferenceable.rb +144 -0
  85. data/lib/garcon/task/event.rb +119 -0
  86. data/lib/garcon/task/executor.rb +275 -0
  87. data/lib/garcon/task/executor_options.rb +59 -0
  88. data/lib/garcon/task/future.rb +107 -0
  89. data/lib/garcon/task/immediate_executor.rb +84 -0
  90. data/lib/garcon/task/ivar.rb +171 -0
  91. data/lib/garcon/task/lazy_reference.rb +74 -0
  92. data/lib/garcon/task/monotonic_time.rb +69 -0
  93. data/lib/garcon/task/obligation.rb +256 -0
  94. data/lib/garcon/task/observable.rb +101 -0
  95. data/lib/garcon/task/priority_queue.rb +234 -0
  96. data/lib/garcon/task/processor_count.rb +128 -0
  97. data/lib/garcon/task/read_write_lock.rb +304 -0
  98. data/lib/garcon/task/safe_task_executor.rb +58 -0
  99. data/lib/garcon/task/single_thread_executor.rb +97 -0
  100. data/lib/garcon/task/thread_pool/cached.rb +71 -0
  101. data/lib/garcon/task/thread_pool/executor.rb +294 -0
  102. data/lib/garcon/task/thread_pool/fixed.rb +61 -0
  103. data/lib/garcon/task/thread_pool/worker.rb +90 -0
  104. data/lib/garcon/task/timer.rb +44 -0
  105. data/lib/garcon/task/timer_set.rb +194 -0
  106. data/lib/garcon/task/timer_task.rb +377 -0
  107. data/lib/garcon/task/waitable_list.rb +58 -0
  108. data/lib/garcon/utility/ansi.rb +199 -0
  109. data/lib/garcon/utility/at_random.rb +77 -0
  110. data/lib/garcon/utility/crypto.rb +292 -0
  111. data/lib/garcon/utility/equalizer.rb +146 -0
  112. data/lib/garcon/utility/faker/extensions/array.rb +22 -0
  113. data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
  114. data/lib/garcon/utility/faker/faker.rb +164 -0
  115. data/lib/garcon/utility/faker/faker/company.rb +17 -0
  116. data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
  117. data/lib/garcon/utility/faker/faker/version.rb +3 -0
  118. data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
  119. data/lib/garcon/utility/faker/locales/en.yml +21 -0
  120. data/lib/garcon/utility/file_helper.rb +170 -0
  121. data/lib/garcon/utility/hookers.rb +178 -0
  122. data/lib/garcon/utility/interpolation.rb +90 -0
  123. data/lib/garcon/utility/memstash.rb +364 -0
  124. data/lib/garcon/utility/misc.rb +54 -0
  125. data/lib/garcon/utility/msg_from_god.rb +62 -0
  126. data/lib/garcon/utility/retry.rb +238 -0
  127. data/lib/garcon/utility/timeout.rb +58 -0
  128. data/lib/garcon/utility/uber/builder.rb +91 -0
  129. data/lib/garcon/utility/uber/callable.rb +7 -0
  130. data/lib/garcon/utility/uber/delegates.rb +13 -0
  131. data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
  132. data/lib/garcon/utility/uber/options.rb +101 -0
  133. data/lib/garcon/utility/uber/uber_version.rb +3 -0
  134. data/lib/garcon/utility/uber/version.rb +33 -0
  135. data/lib/garcon/utility/url_helper.rb +100 -0
  136. data/lib/garcon/utils.rb +29 -0
  137. data/lib/garcon/version.rb +62 -0
  138. data/lib/garcun.rb +24 -0
  139. metadata +680 -0
@@ -0,0 +1,66 @@
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 #blank? method to TrueClass class.
21
+ class TrueClass
22
+ # True is never blank.
23
+ #
24
+ # @example
25
+ # true.blank? # => false
26
+ #
27
+ # @return [FalseClass]
28
+ #
29
+ # @api public
30
+ def blank?
31
+ false
32
+ end
33
+
34
+ # Since TrueClass is immutable it cannot be duplicated.
35
+ # For this reason #try_dup returns +self+.
36
+ #
37
+ # true.dup! #=> true
38
+ #
39
+ def dup! ; self ; end
40
+ def dup? ; false ; end
41
+ def clone? ; false ; end
42
+ end
43
+
44
+ # Add #blank? method to FalseClass class.
45
+ class FalseClass
46
+ # False is always blank.
47
+ #
48
+ # @example
49
+ # false.blank? # => true
50
+ #
51
+ # @return [TrueClass]
52
+ #
53
+ # @api public
54
+ def blank?
55
+ true
56
+ end
57
+
58
+ # Since FalseClass is immutable it cannot be duplicated.
59
+ # For this reason #try_dup returns +self+.
60
+ #
61
+ # false.dup! #=> false
62
+ #
63
+ def dup! ; self ; end
64
+ def dup? ; false ; end
65
+ def clone? ; false ; end
66
+ end
@@ -0,0 +1,271 @@
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
+ class Duration
21
+ include Comparable
22
+
23
+ SECOND = 1
24
+ MINUTE = 60 * SECOND
25
+ HOUR = 60 * MINUTE
26
+ DAY = 24 * HOUR
27
+ WEEK = 7 * DAY
28
+ YEAR = 365 * DAY
29
+
30
+ SEGMENTS = %w{years weeks days hours minutes seconds}.collect{ |s| s.to_sym }
31
+
32
+ def self.[](seconds, *segments)
33
+ new(seconds, *segments)
34
+ end
35
+
36
+ def initialize(seconds=0, *segments)
37
+ @seconds = seconds.to_i
38
+ reset_segments(*segments)
39
+ end
40
+
41
+ def segments; @segments; end
42
+
43
+ def reset_segments(*segments)
44
+ case segments.size
45
+ when 0
46
+ @segments = [:days, :hours, :minutes, :seconds]
47
+ when 1
48
+ case segments = segments[0]
49
+ when Array
50
+ @segments = segments.collect { |p| (p.to_s.downcase.chomp('s') + 's').to_sym }
51
+ raise ArgumentError unless @segments.all? { |s| SEGMENTS.include?(s) }
52
+ else
53
+ f = SEGMENTS.index(segments)
54
+ @segments = SEGMENTS[f..0]
55
+ end
56
+ when 2
57
+ f = SEGMENTS.index(segments[0])
58
+ t = SEGMENTS.index(segments[1])
59
+ @segments = SEGMENTS[f..t]
60
+ else
61
+ raise ArgumentError
62
+ end
63
+ end
64
+
65
+ def inspect
66
+ h = to_h
67
+ segments.reverse.collect do |l|
68
+ "#{h[l.to_sym]} #{l}"
69
+ end.join(' ')
70
+ end
71
+
72
+ def to_i ; @seconds.to_i ; end
73
+ def to_f ; @seconds.to_f ; end
74
+
75
+ public
76
+
77
+ def to_a
78
+ a, s = [], @seconds
79
+ a[5], s = *s.divmod(YEAR) if @segments.include?(:years)
80
+ a[4], s = *s.divmod(WEEK) if @segments.include?(:weeks)
81
+ a[3], s = *s.divmod(DAY) if @segments.include?(:days)
82
+ a[2], s = *s.divmod(HOUR) if @segments.include?(:hours)
83
+ a[1], s = *s.divmod(MINUTE) if @segments.include?(:minutes)
84
+ a[0], s = *s.divmod(SECOND) if @segments.include?(:seconds)
85
+ a.compact.reverse
86
+ end
87
+
88
+ def to_h
89
+ h, s = {}, @seconds
90
+ h[:years], s = *s.divmod(YEAR) if @segments.include?(:years)
91
+ h[:weeks], s = *s.divmod(WEEK) if @segments.include?(:weeks)
92
+ h[:days], s = *s.divmod(DAY) if @segments.include?(:days)
93
+ h[:hours], s = *s.divmod(HOUR) if @segments.include?(:hours)
94
+ h[:minutes], s = *s.divmod(MINUTE) if @segments.include?(:minutes)
95
+ h[:seconds], s = *s.divmod(SECOND) if @segments.include?(:seconds)
96
+ h
97
+ end
98
+
99
+ def to_s
100
+ h = to_h
101
+ segments.reverse.collect do |l|
102
+ "#{h[l.to_sym]} #{l}"
103
+ end.join(' ')
104
+ end
105
+
106
+ def ==(other)
107
+ if Duration === other
108
+ other.seconds == seconds
109
+ else
110
+ other == seconds
111
+ end
112
+ end
113
+
114
+ def <=>(other)
115
+ @seconds <=> other.to_i
116
+ end
117
+
118
+ def years ; to_h[:years] ; end
119
+ def weeks ; to_h[:weeks] ; end
120
+ def days ; to_h[:days] ; end
121
+ def hours ; to_h[:hours] ; end
122
+ def minutes ; to_h[:minutes] ; end
123
+ def seconds ; to_h[:seconds] ; end
124
+
125
+ def total ; seconds ; end
126
+
127
+ def +(other)
128
+ self.class.new(@seconds + other.to_i, segments)
129
+ end
130
+
131
+ def -(other)
132
+ self.class.new(@seconds - other.to_i, segments)
133
+ end
134
+
135
+ def *(other)
136
+ self.class.new(@seconds * other.to_i, segments)
137
+ end
138
+
139
+ def /(other)
140
+ self.class.new(@seconds / other.to_i, segments)
141
+ end
142
+
143
+ def segmented(*segments)
144
+ self.class.new(@seconds, segments)
145
+ end
146
+
147
+ # Format duration.
148
+ #
149
+ # *Identifiers*
150
+ #
151
+ # %w -- Number of weeks
152
+ # %d -- Number of days
153
+ # %h -- Number of hours
154
+ # %m -- Number of minutes
155
+ # %s -- Number of seconds
156
+ # %t -- Total number of seconds
157
+ # %x -- Duration#to_s
158
+ # %% -- Literal `%' character
159
+ #
160
+ # *Example*
161
+ #
162
+ # d = Duration.new(:weeks => 10, :days => 7)
163
+ # => #<Duration: 11 weeks>
164
+ # d.strftime("It's been %w weeks!")
165
+ # => "It's been 11 weeks!"
166
+ #
167
+ def strftime(fmt)
168
+ h = to_h
169
+ hx = {
170
+ 'y' => h[:years] ,
171
+ 'w' => h[:weeks] ,
172
+ 'd' => h[:days] ,
173
+ 'h' => h[:hours] ,
174
+ 'm' => h[:minutes],
175
+ 's' => h[:seconds],
176
+ 't' => total,
177
+ 'x' => to_s
178
+ }
179
+ fmt.gsub(/%?%(w|d|h|m|s|t|x)/) do |match|
180
+ hx[match[1..1]]
181
+ end.gsub('%%', '%')
182
+ end
183
+
184
+ def -@
185
+ self.class.new(-@seconds)
186
+ end
187
+
188
+ def +@
189
+ self.class.new(+@seconds)
190
+ end
191
+
192
+ def before(time)
193
+ @seconds.before(time)
194
+ end
195
+
196
+ def after(time)
197
+ @seconds.after(time)
198
+ end
199
+
200
+
201
+ # = Numeric Extensions for Durations
202
+ #
203
+ module Numeric
204
+
205
+ # Enables the use of time calculations and declarations,
206
+ # like 45.minutes + 2.hours + 4.years. The base unit for
207
+ # all of these Numeric time methods is seconds.
208
+ def seconds ; Duration[self] ; end
209
+ alias_method :second, :seconds
210
+
211
+ # Converts minutes into seconds.
212
+ def minutes ; Duration[self * 60] ; end
213
+ alias_method :minute, :minutes
214
+
215
+ # Converts hours into seconds.
216
+ def hours ; Duration[self * 3600] ; end
217
+ alias_method :hour, :hours
218
+ #def as_hours ; self / 60.minutes ; end
219
+
220
+ # Converts days into seconds.
221
+ def days ; Duration[self * 86400] ; end
222
+ alias_method :day, :days
223
+
224
+ # Converts weeks into seconds.
225
+ def weeks ; Duration[self * 604800] ; end
226
+ alias_method :week, :weeks
227
+
228
+ # Converts fortnights into seconds.
229
+ # (A fortnight is 2 weeks)
230
+ def fortnights ; Duration[self * 1209600] ; end
231
+ alias_method :fortnight, :fortnights
232
+
233
+ # Converts months into seconds.
234
+ # WARNING: This is not exact as it assumes 30 days to a month.
235
+ def months ; Duration[self * 30 * 86400] ; end
236
+ alias_method :month, :months
237
+
238
+ # Converts years into seconds.
239
+ # WARNING: This is not exact as it assumes 365 days to a year.
240
+ # ie. It doesn not account for leap years.
241
+ def years ; Duration[self * 365 * 86400, :years] ; end
242
+ alias_method :year, :years
243
+
244
+ end
245
+
246
+ # Time#duration has been added to convert the UNIX timestamp into a Duration.
247
+ # See Time#duration for an example.
248
+ #
249
+ module Time
250
+ # Create a Duration object from the UNIX timestamp.
251
+ #
252
+ # *Example*
253
+ #
254
+ # Time.now.duration
255
+ # => #<Duration: 1898 weeks, 6 days, 1 hour, 12 minutes and 1 second>
256
+ #
257
+ def duration
258
+ Duration[to_i]
259
+ end
260
+ end
261
+
262
+ end
263
+
264
+ class Numeric
265
+ include Duration::Numeric
266
+ end
267
+
268
+ class Time
269
+ include Duration::Time
270
+ end
271
+
@@ -0,0 +1,34 @@
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 #exclude
21
+ module Enumerable
22
+ unless method_defined?(:exclude?)
23
+ # The inverse of #include?.
24
+ #
25
+ # @example
26
+ # [:a, :b].exclude?(:c) # => true
27
+ # [:a, :b].exclude?(:a) # => false
28
+ #
29
+ # @api public
30
+ def exclude?(object)
31
+ !include?(object)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,127 @@
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 'thread' unless defined?(Thread)
21
+ require 'tempfile' unless defined?(Tempfile)
22
+ require 'fileutils' unless defined?(FileUtils)
23
+
24
+ class File
25
+
26
+ def self.atomic_id
27
+ @atomic_id ||= 0
28
+ @atomic_id += 1
29
+ end
30
+
31
+ # Same as `File.open`, but acts on a temporary copy of named
32
+ # file, copying the file back to the original on completion.
33
+ #
34
+ # @uncommon
35
+ # require 'facets/fileutils/atomic_open'
36
+ #
37
+ def self.atomic_open(file_name, mode="r", temp_dir=nil, &block)
38
+ temp_dir = temp_dir || Dir.tmpdir
39
+ temp_file = Tempfile.new("#{aomtic_id}-" + basename(file_name), temp_dir)
40
+
41
+ if File.exist?(file_name)
42
+ FileUtils.cp(file_name, temp_file)
43
+ end
44
+
45
+ open(temp_file, mode, &block)
46
+
47
+ FileUtils.cp(temp_file, file_name)
48
+ end
49
+
50
+ # Write to a file atomically. Useful for situations where you don't
51
+ # want other processes or threads to see half-written files.
52
+ #
53
+ # File.atomic_write("important.txt") do |file|
54
+ # file.write("hello")
55
+ # end
56
+ #
57
+ # If your temporary directory is not on the same filesystem as the file you're
58
+ # trying to write, you can provide a different temporary directory.
59
+ #
60
+ # File.atomic_write("important.txt", "tmp") do |file|
61
+ # file.write("hello")
62
+ # end
63
+ #
64
+ # NOTE: This method is not a common core extension and is not
65
+ # loaded automatically when using <code>require 'facets'</code>.
66
+ #
67
+ # CREDIT: David Heinemeier Hansson
68
+ #
69
+ # @uncommon
70
+ # require 'facets/fileutils/atomic_write'
71
+ #
72
+ def self.atomic_write(file_name, temp_dir=nil)
73
+ temp_dir = temp_dir || Dir.tmpdir
74
+ temp_file = Tempfile.new(basename(file_name), temp_dir)
75
+
76
+ yield temp_file
77
+ temp_file.close
78
+
79
+ begin
80
+ ## Get original file permissions
81
+ old_stat = stat(file_name)
82
+ rescue Errno::ENOENT
83
+ ## No old permissions, write a temp file to determine the defaults
84
+ check_name = join(dirname(file_name), ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}")
85
+ open(check_name, "w") { }
86
+ old_stat = stat(check_name)
87
+ unlink(check_name)
88
+ end
89
+
90
+ ## Overwrite original file with temp file
91
+ FileUtils.mv(temp_file.path, file_name)
92
+
93
+ ## Set correct permissions on new file
94
+ chown(old_stat.uid, old_stat.gid, file_name)
95
+ chmod(old_stat.mode, file_name)
96
+ end
97
+
98
+ # Reads in a file, removes blank lines and removes lines starting
99
+ # with '#' and then returns an array of all the remaining lines.
100
+ #
101
+ # Thr remark indicator can be overridden via the +:omit:+ option, which
102
+ # can be a regualar expression or a string that is match against the
103
+ # start of a line.
104
+ #
105
+ # CREDIT: Trans
106
+
107
+ def self.read_list(filepath, options={})
108
+ chomp = options[:chomp]
109
+ omit = case options[:omit]
110
+ when Regexp
111
+ omit
112
+ when nil
113
+ /^\s*\#/
114
+ else
115
+ /^\s*#{Regexp.escape(omit)}/
116
+ end
117
+
118
+ list = []
119
+ readlines(filepath).each do |line|
120
+ line = line.strip.chomp(chomp)
121
+ next if line.empty?
122
+ next if omit === line
123
+ list << line
124
+ end
125
+ list
126
+ end
127
+ end