larrow-runner 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/RELEASE +16 -0
- data/larrow-runner.gemspec +1 -1
- data/lib/active_support/core_ext/hash.rb +0 -6
- data/lib/active_support/core_ext/string.rb +1 -0
- data/lib/active_support/core_ext/string/indent.rb +43 -0
- data/lib/larrow/runner/cli/tools.rb +2 -2
- data/lib/larrow/runner/manager.rb +2 -1
- data/lib/larrow/runner/manifest/adapter/travis.rb +1 -1
- data/lib/larrow/runner/manifest/configuration.rb +6 -3
- data/lib/larrow/runner/model/app.rb +3 -2
- data/lib/larrow/runner/model/node.rb +2 -2
- data/lib/larrow/runner/service/cloud.rb +13 -0
- data/lib/larrow/runner/service/executor.rb +2 -2
- data/lib/larrow/runner/vcs/file_system.rb +18 -7
- data/lib/larrow/runner/version.rb +1 -1
- data/spec/{manifest → unit_test/manifest}/travis_spec.rb +2 -2
- data/spec/{model → unit_test/model}/node_spec.rb +3 -3
- data/spec/{service → unit_test/service}/executor_spec.rb +3 -6
- data/spec/{vcs → unit_test/vcs}/github_spec.rb +1 -1
- metadata +21 -17
- data/lib/active_support/core_ext/hash/compact.rb +0 -20
- data/lib/active_support/core_ext/hash/deep_merge.rb +0 -38
- data/lib/active_support/core_ext/hash/except.rb +0 -15
- data/lib/active_support/core_ext/hash/reverse_merge.rb +0 -22
- data/lib/active_support/core_ext/hash/slice.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c95b382b38fc64696236c9787628559fc98370b
|
4
|
+
data.tar.gz: 885f40783bd3a22542e4093833d96bbe75d3b776
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b7a87e391867ed386e7e53cb4a5db5064eb5e475640e6dfff776ba7474a099966c236071db37eec2aef5157442c4ec114860019e91d54dac03e4852b09c0cc3
|
7
|
+
data.tar.gz: 5f9629bc468942d32aa3570e32802db24397b516627fc77f19af0408f99045f835704cda3286262145c7eedcbddafc2a29f35118cc2203ffd85d5309f00cce8c
|
data/RELEASE
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
2014.11.02. version 0.0.3
|
2
|
+
=========================
|
3
|
+
|
4
|
+
* clean dependency: remove `active_support`
|
5
|
+
* open verbose mode on tests
|
6
|
+
* delete resource file when cleanup
|
7
|
+
* ensure node start( use `nmap` to detect)
|
8
|
+
* use larrow-qingcloud v0.0.2
|
9
|
+
|
10
|
+
2014.10.19. version 0.0.2
|
11
|
+
=========================
|
12
|
+
|
13
|
+
* hotfix: undefined method `address` for Node
|
14
|
+
* remove some third party libs
|
15
|
+
* check cloud login before execute
|
16
|
+
* some changes for user convenience
|
data/larrow-runner.gemspec
CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
|
34
34
|
spec.add_runtime_dependency "faraday", '~> 0.9'
|
35
35
|
|
36
|
-
spec.add_runtime_dependency 'larrow-qingcloud', '~> 0'
|
36
|
+
spec.add_runtime_dependency 'larrow-qingcloud', '~> 0.0', '>= 0.0.2'
|
37
37
|
spec.add_runtime_dependency 'promising', '~> 0.3'
|
38
38
|
|
39
39
|
end
|
@@ -1,7 +1 @@
|
|
1
|
-
require 'active_support/core_ext/hash/compact'
|
2
|
-
require 'active_support/core_ext/hash/deep_merge'
|
3
|
-
require 'active_support/core_ext/hash/except'
|
4
1
|
require 'active_support/core_ext/hash/indifferent_access'
|
5
|
-
require 'active_support/core_ext/hash/keys'
|
6
|
-
require 'active_support/core_ext/hash/reverse_merge'
|
7
|
-
require 'active_support/core_ext/hash/slice'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_support/core_ext/string/indent'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class String
|
2
|
+
# Same as +indent+, except it indents the receiver in-place.
|
3
|
+
#
|
4
|
+
# Returns the indented string, or +nil+ if there was nothing to indent.
|
5
|
+
def indent!(amount, indent_string=nil, indent_empty_lines=false)
|
6
|
+
indent_string = indent_string || self[/^[ \t]/] || ' '
|
7
|
+
re = indent_empty_lines ? /^/ : /^(?!$)/
|
8
|
+
gsub!(re, indent_string * amount)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Indents the lines in the receiver:
|
12
|
+
#
|
13
|
+
# <<EOS.indent(2)
|
14
|
+
# def some_method
|
15
|
+
# some_code
|
16
|
+
# end
|
17
|
+
# EOS
|
18
|
+
# # =>
|
19
|
+
# def some_method
|
20
|
+
# some_code
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# The second argument, +indent_string+, specifies which indent string to
|
24
|
+
# use. The default is +nil+, which tells the method to make a guess by
|
25
|
+
# peeking at the first indented line, and fallback to a space if there is
|
26
|
+
# none.
|
27
|
+
#
|
28
|
+
# " foo".indent(2) # => " foo"
|
29
|
+
# "foo\n\t\tbar".indent(2) # => "\t\tfoo\n\t\t\t\tbar"
|
30
|
+
# "foo".indent(2, "\t") # => "\t\tfoo"
|
31
|
+
#
|
32
|
+
# While +indent_string+ is typically one space or tab, it may be any string.
|
33
|
+
#
|
34
|
+
# The third argument, +indent_empty_lines+, is a flag that says whether
|
35
|
+
# empty lines should be indented. Default is false.
|
36
|
+
#
|
37
|
+
# "foo\n\nbar".indent(2) # => " foo\n\n bar"
|
38
|
+
# "foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar"
|
39
|
+
#
|
40
|
+
def indent(amount, indent_string=nil, indent_empty_lines=false)
|
41
|
+
dup.tap {|_| _.indent!(amount, indent_string, indent_empty_lines)}
|
42
|
+
end
|
43
|
+
end
|
@@ -18,7 +18,7 @@ You can save it as .larrow.yml on the project root folder.
|
|
18
18
|
|
19
19
|
desc 'resource','show all resource in Resource.yml'
|
20
20
|
long_desc <<-EOF.gsub("\n", "\x5")
|
21
|
-
Read
|
21
|
+
Read #{ResourcePath} from current directory, show information.
|
22
22
|
resource: instance, eip, etc...
|
23
23
|
EOF
|
24
24
|
def resource
|
@@ -27,7 +27,7 @@ resource: instance, eip, etc...
|
|
27
27
|
|
28
28
|
desc 'cleanup','cleanup all resource in Resource.yml'
|
29
29
|
long_desc <<-EOF.gsub("\n", "\x5")
|
30
|
-
Read
|
30
|
+
Read #{ResourcePath} from current directory, and release all resources.
|
31
31
|
resource: instance, eip, etc...
|
32
32
|
EOF
|
33
33
|
def cleanup
|
@@ -77,7 +77,7 @@ module Larrow::Runner
|
|
77
77
|
|
78
78
|
def store_resource
|
79
79
|
resource = app.dump
|
80
|
-
File.write
|
80
|
+
File.write ResourcePath, YAML.dump(resource)
|
81
81
|
RunLogger.title 'store resource'
|
82
82
|
end
|
83
83
|
|
@@ -102,6 +102,7 @@ module Larrow::Runner
|
|
102
102
|
resource_iterator do |clazz, array|
|
103
103
|
clazz.cleanup array
|
104
104
|
end
|
105
|
+
File.delete ResourcePath rescue nil
|
105
106
|
RunLogger.title 'resource cleaned'
|
106
107
|
end
|
107
108
|
|
@@ -81,9 +81,12 @@ module Larrow::Runner
|
|
81
81
|
self.title = title
|
82
82
|
end
|
83
83
|
|
84
|
-
def run_on node
|
84
|
+
def run_on node, verbose:nil
|
85
|
+
verbose = title.to_s.end_with?('test') if verbose.nil?
|
85
86
|
scripts.each do |script|
|
86
|
-
node.execute
|
87
|
+
node.execute(script.actual_command,
|
88
|
+
base_dir: script.base_dir,
|
89
|
+
verbose: verbose)
|
87
90
|
end
|
88
91
|
end
|
89
92
|
end
|
@@ -99,7 +102,7 @@ module Larrow::Runner
|
|
99
102
|
self.block = block
|
100
103
|
end
|
101
104
|
|
102
|
-
def run_on node
|
105
|
+
def run_on node, *args
|
103
106
|
block.call node
|
104
107
|
end
|
105
108
|
end
|
@@ -16,12 +16,13 @@ module Larrow::Runner
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def action group
|
19
|
+
verbose = RunOption.key?(:debug) ? true : nil
|
19
20
|
configuration.steps_for(group) do |a_step|
|
20
21
|
RunLogger.title "[#{a_step.title}]"
|
21
22
|
begin_at = Time.new
|
22
|
-
a_step.run_on node
|
23
|
+
a_step.run_on node, verbose: verbose
|
23
24
|
during = sprintf('%.2f',Time.new - begin_at)
|
24
|
-
RunLogger.level(1).
|
25
|
+
RunLogger.level(1).info "#{a_step.title} complete (#{during}s)"
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -14,7 +14,7 @@ module Larrow::Runner
|
|
14
14
|
@executor = Executor.new host, user, nil, nil
|
15
15
|
end
|
16
16
|
|
17
|
-
def execute command, base_dir:nil
|
17
|
+
def execute command, base_dir:nil,verbose:nil
|
18
18
|
block = if block_given?
|
19
19
|
-> (data) { yield data }
|
20
20
|
else
|
@@ -24,7 +24,7 @@ module Larrow::Runner
|
|
24
24
|
end
|
25
25
|
}
|
26
26
|
end
|
27
|
-
@executor.execute command, base_dir: base_dir, &block
|
27
|
+
@executor.execute command, base_dir: base_dir, verbose:verbose, &block
|
28
28
|
end
|
29
29
|
|
30
30
|
def stop
|
@@ -30,6 +30,8 @@ module Larrow
|
|
30
30
|
RunLogger.level(1).detail "bind ip: #{eips[i].address}"
|
31
31
|
eips[i] = eips[i].associate instances[i].id
|
32
32
|
[ instances[i], eips[i] ]
|
33
|
+
end.tap do |list|
|
34
|
+
list.each{|instance,eip| ping eip.address,30}
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -54,6 +56,17 @@ module Larrow
|
|
54
56
|
Qingcloud.remove_connection
|
55
57
|
raise $!
|
56
58
|
end
|
59
|
+
|
60
|
+
def ping host, time, port=22
|
61
|
+
Timeout::timeout(time) do
|
62
|
+
loop do
|
63
|
+
if system("nmap #{host} -p #{port} -Pn | grep -q open")
|
64
|
+
return true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
57
70
|
end
|
58
71
|
end
|
59
72
|
end
|
@@ -15,13 +15,13 @@ module Larrow
|
|
15
15
|
@dlogger = RunLogger #::Logger.new "#{ip}_cmd.log"
|
16
16
|
end
|
17
17
|
|
18
|
-
def execute cmd, base_dir:nil
|
18
|
+
def execute cmd, base_dir:nil,verbose:nil
|
19
19
|
connection.open_channel do |ch|
|
20
20
|
RunLogger.level(1).detail "# #{cmd}"
|
21
21
|
cmd = "cd #{base_dir}; #{cmd}" unless base_dir.nil?
|
22
22
|
errmsg = ''
|
23
23
|
ch.exec cmd do |ch,success|
|
24
|
-
if
|
24
|
+
if verbose
|
25
25
|
ch.on_data{ |c, data| yield data }
|
26
26
|
ch.on_extended_data{ |c, type, data| yield data }
|
27
27
|
else
|
@@ -27,7 +27,7 @@ module Larrow::Runner
|
|
27
27
|
def update_source node, target_dir
|
28
28
|
command = rsync_command node.user, node.host,target_dir
|
29
29
|
invoke command
|
30
|
-
|
30
|
+
`ssh-keygen -R #{node.host} 2>&1 >/dev/null`
|
31
31
|
end
|
32
32
|
|
33
33
|
def rsync_command user, host, target_dir
|
@@ -40,19 +40,30 @@ module Larrow::Runner
|
|
40
40
|
unshift('.git'). # .git itself is ignored
|
41
41
|
map{|s| "--exclude '#{s}'" } # build rsync exclude arguments
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
rsync_options = "-az #{ssh_options} #{excludes.join ' '}"
|
43
|
+
rsync_options = "-az -e 'ssh #{ssh_options}' #{excludes.join ' '}"
|
46
44
|
rsync_options += ' -v' if RunOption.key? :debug
|
47
45
|
|
48
|
-
"rsync #{rsync_options} #{project_folder}/ '#{ssh_path}'
|
46
|
+
"rsync #{rsync_options} #{project_folder}/ '#{ssh_path}'"
|
49
47
|
end
|
48
|
+
|
50
49
|
def invoke command
|
51
|
-
|
52
|
-
|
50
|
+
RunLogger.level(1).info command
|
51
|
+
time = Time.new
|
52
|
+
`#{command} 2>&1`.split(/\r?\n/).each do |msg|
|
53
|
+
RunLogger.level(2).detail msg
|
53
54
|
end
|
55
|
+
RunLogger.level(1).detail "invoke time: #{Time.new - time}"
|
54
56
|
end
|
55
57
|
|
58
|
+
def ssh_options
|
59
|
+
{
|
60
|
+
'GSSAPIAuthentication' => 'no',
|
61
|
+
'StrictHostKeyChecking' => 'no',
|
62
|
+
'LogLevel' => 'ERROR'
|
63
|
+
}.map do |k,v|
|
64
|
+
"-o #{k}=#{v}"
|
65
|
+
end.join(' ')
|
66
|
+
end
|
56
67
|
end
|
57
68
|
end
|
58
69
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative '../../spec_helper.rb'
|
2
2
|
|
3
3
|
module Larrow::Runner::Manifest
|
4
4
|
describe Travis do
|
@@ -9,7 +9,7 @@ module Larrow::Runner::Manifest
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def get _filename
|
12
|
-
path = File.expand_path "
|
12
|
+
path = File.expand_path "../../../fixtures/#{filename}", __FILE__
|
13
13
|
File.read(path)
|
14
14
|
end
|
15
15
|
|
@@ -1,15 +1,15 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative '../../spec_helper.rb'
|
2
2
|
|
3
3
|
module Larrow::Runner::Model
|
4
4
|
describe Node do
|
5
5
|
subject{ Node.new nil, OpenStruct.new(address: 'localhost'), `whoami`.chomp }
|
6
6
|
before do
|
7
|
-
Larrow::Runner::RunOption[:debug] =
|
7
|
+
Larrow::Runner::RunOption[:debug] = true
|
8
8
|
end
|
9
9
|
it 'can execute' do
|
10
10
|
outputs = ""
|
11
11
|
script = OpenStruct.new(actual_command: 'pwd')
|
12
|
-
subject.execute('pwd') do |data|
|
12
|
+
subject.execute('pwd',verbose:true) do |data|
|
13
13
|
outputs << data
|
14
14
|
end
|
15
15
|
expect(outputs).to include(ENV['HOME'])
|
@@ -1,19 +1,16 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative '../../spec_helper.rb'
|
2
2
|
module Larrow::Runner::Service
|
3
3
|
describe Executor do
|
4
4
|
subject{ Executor.new 'localhost', `whoami`.chomp, 22, nil }
|
5
|
-
before do
|
6
|
-
Larrow::Runner::RunOption[:debug] = nil
|
7
|
-
end
|
8
5
|
it 'normal command run'do
|
9
6
|
outputs = ''
|
10
|
-
subject.execute('echo aaa'){|data| outputs << data}
|
7
|
+
subject.execute('echo aaa',verbose:true){|data| outputs << data}
|
11
8
|
expect(outputs).to eq "aaa\n"
|
12
9
|
end
|
13
10
|
|
14
11
|
it 'command with base dir' do
|
15
12
|
outputs = ''
|
16
|
-
subject.execute('pwd', base_dir: '/opt') do |data|
|
13
|
+
subject.execute('pwd', base_dir: '/opt',verbose:true) do |data|
|
17
14
|
outputs << data
|
18
15
|
end
|
19
16
|
expect(outputs).to eq "/opt\n"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: larrow-runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- fsword
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -182,14 +182,20 @@ dependencies:
|
|
182
182
|
requirements:
|
183
183
|
- - "~>"
|
184
184
|
- !ruby/object:Gem::Version
|
185
|
-
version: '0'
|
185
|
+
version: '0.0'
|
186
|
+
- - ">="
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: 0.0.2
|
186
189
|
type: :runtime
|
187
190
|
prerelease: false
|
188
191
|
version_requirements: !ruby/object:Gem::Requirement
|
189
192
|
requirements:
|
190
193
|
- - "~>"
|
191
194
|
- !ruby/object:Gem::Version
|
192
|
-
version: '0'
|
195
|
+
version: '0.0'
|
196
|
+
- - ">="
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: 0.0.2
|
193
199
|
- !ruby/object:Gem::Dependency
|
194
200
|
name: promising
|
195
201
|
requirement: !ruby/object:Gem::Requirement
|
@@ -218,17 +224,15 @@ files:
|
|
218
224
|
- Gemfile
|
219
225
|
- LICENSE.txt
|
220
226
|
- README.md
|
227
|
+
- RELEASE
|
221
228
|
- Rakefile
|
222
229
|
- bin/larrow
|
223
230
|
- larrow-runner.gemspec
|
224
231
|
- lib/active_support/core_ext/hash.rb
|
225
|
-
- lib/active_support/core_ext/hash/compact.rb
|
226
|
-
- lib/active_support/core_ext/hash/deep_merge.rb
|
227
|
-
- lib/active_support/core_ext/hash/except.rb
|
228
232
|
- lib/active_support/core_ext/hash/indifferent_access.rb
|
229
233
|
- lib/active_support/core_ext/hash/keys.rb
|
230
|
-
- lib/active_support/core_ext/
|
231
|
-
- lib/active_support/core_ext/
|
234
|
+
- lib/active_support/core_ext/string.rb
|
235
|
+
- lib/active_support/core_ext/string/indent.rb
|
232
236
|
- lib/active_support/hash_with_indifferent_access.rb
|
233
237
|
- lib/larrow/runner.rb
|
234
238
|
- lib/larrow/runner/cli.rb
|
@@ -260,11 +264,11 @@ files:
|
|
260
264
|
- spec/fixtures/travis_ruby.yml
|
261
265
|
- spec/integration/build_cmds_spec.rb
|
262
266
|
- spec/integration/test_cmds_spec.rb
|
263
|
-
- spec/manifest/travis_spec.rb
|
264
|
-
- spec/model/node_spec.rb
|
265
|
-
- spec/service/executor_spec.rb
|
266
267
|
- spec/spec_helper.rb
|
267
|
-
- spec/
|
268
|
+
- spec/unit_test/manifest/travis_spec.rb
|
269
|
+
- spec/unit_test/model/node_spec.rb
|
270
|
+
- spec/unit_test/service/executor_spec.rb
|
271
|
+
- spec/unit_test/vcs/github_spec.rb
|
268
272
|
homepage: http://github.com/fsword/larrow-core
|
269
273
|
licenses:
|
270
274
|
- MIT
|
@@ -294,8 +298,8 @@ test_files:
|
|
294
298
|
- spec/fixtures/travis_ruby.yml
|
295
299
|
- spec/integration/build_cmds_spec.rb
|
296
300
|
- spec/integration/test_cmds_spec.rb
|
297
|
-
- spec/manifest/travis_spec.rb
|
298
|
-
- spec/model/node_spec.rb
|
299
|
-
- spec/service/executor_spec.rb
|
300
301
|
- spec/spec_helper.rb
|
301
|
-
- spec/
|
302
|
+
- spec/unit_test/manifest/travis_spec.rb
|
303
|
+
- spec/unit_test/model/node_spec.rb
|
304
|
+
- spec/unit_test/service/executor_spec.rb
|
305
|
+
- spec/unit_test/vcs/github_spec.rb
|
@@ -1,20 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
# Returns a hash with non +nil+ values.
|
3
|
-
#
|
4
|
-
# hash = { a: true, b: false, c: nil}
|
5
|
-
# hash.compact # => { a: true, b: false}
|
6
|
-
# hash # => { a: true, b: false, c: nil}
|
7
|
-
# { c: nil }.compact # => {}
|
8
|
-
def compact
|
9
|
-
self.select { |_, value| !value.nil? }
|
10
|
-
end
|
11
|
-
|
12
|
-
# Replaces current hash with non +nil+ values.
|
13
|
-
#
|
14
|
-
# hash = { a: true, b: false, c: nil}
|
15
|
-
# hash.compact! # => { a: true, b: false}
|
16
|
-
# hash # => { a: true, b: false}
|
17
|
-
def compact!
|
18
|
-
self.reject! { |_, value| value.nil? }
|
19
|
-
end
|
20
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
3
|
-
#
|
4
|
-
# h1 = { a: true, b: { c: [1, 2, 3] } }
|
5
|
-
# h2 = { a: false, b: { x: [3, 4, 5] } }
|
6
|
-
#
|
7
|
-
# h1.deep_merge(h2) #=> { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
|
8
|
-
#
|
9
|
-
# Like with Hash#merge in the standard library, a block can be provided
|
10
|
-
# to merge values:
|
11
|
-
#
|
12
|
-
# h1 = { a: 100, b: 200, c: { c1: 100 } }
|
13
|
-
# h2 = { b: 250, c: { c1: 200 } }
|
14
|
-
# h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
|
15
|
-
# # => { a: 100, b: 450, c: { c1: 300 } }
|
16
|
-
def deep_merge(other_hash, &block)
|
17
|
-
dup.deep_merge!(other_hash, &block)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Same as +deep_merge+, but modifies +self+.
|
21
|
-
def deep_merge!(other_hash, &block)
|
22
|
-
other_hash.each_pair do |current_key, other_value|
|
23
|
-
this_value = self[current_key]
|
24
|
-
|
25
|
-
self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
|
26
|
-
this_value.deep_merge(other_value, &block)
|
27
|
-
else
|
28
|
-
if block_given? && key?(current_key)
|
29
|
-
block.call(current_key, this_value, other_value)
|
30
|
-
else
|
31
|
-
other_value
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
self
|
37
|
-
end
|
38
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
# Returns a hash that includes everything but the given keys. This is useful for
|
3
|
-
# limiting a set of parameters to everything but a few known toggles:
|
4
|
-
#
|
5
|
-
# @person.update(params[:person].except(:admin))
|
6
|
-
def except(*keys)
|
7
|
-
dup.except!(*keys)
|
8
|
-
end
|
9
|
-
|
10
|
-
# Replaces the hash without the given keys.
|
11
|
-
def except!(*keys)
|
12
|
-
keys.each { |key| delete(key) }
|
13
|
-
self
|
14
|
-
end
|
15
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
# Merges the caller into +other_hash+. For example,
|
3
|
-
#
|
4
|
-
# options = options.reverse_merge(size: 25, velocity: 10)
|
5
|
-
#
|
6
|
-
# is equivalent to
|
7
|
-
#
|
8
|
-
# options = { size: 25, velocity: 10 }.merge(options)
|
9
|
-
#
|
10
|
-
# This is particularly useful for initializing an options hash
|
11
|
-
# with default values.
|
12
|
-
def reverse_merge(other_hash)
|
13
|
-
other_hash.merge(self)
|
14
|
-
end
|
15
|
-
|
16
|
-
# Destructive +reverse_merge+.
|
17
|
-
def reverse_merge!(other_hash)
|
18
|
-
# right wins if there is no left
|
19
|
-
merge!( other_hash ){|key,left,right| left }
|
20
|
-
end
|
21
|
-
alias_method :reverse_update, :reverse_merge!
|
22
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
# Slice a hash to include only the given keys. This is useful for
|
3
|
-
# limiting an options hash to valid keys before passing to a method:
|
4
|
-
#
|
5
|
-
# def search(criteria = {})
|
6
|
-
# criteria.assert_valid_keys(:mass, :velocity, :time)
|
7
|
-
# end
|
8
|
-
#
|
9
|
-
# search(options.slice(:mass, :velocity, :time))
|
10
|
-
#
|
11
|
-
# If you have an array of keys you want to limit to, you should splat them:
|
12
|
-
#
|
13
|
-
# valid_keys = [:mass, :velocity, :time]
|
14
|
-
# search(options.slice(*valid_keys))
|
15
|
-
def slice(*keys)
|
16
|
-
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
|
17
|
-
keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
|
18
|
-
end
|
19
|
-
|
20
|
-
# Replaces the hash with only the given keys.
|
21
|
-
# Returns a hash containing the removed key/value pairs.
|
22
|
-
#
|
23
|
-
# { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b)
|
24
|
-
# # => {:c=>3, :d=>4}
|
25
|
-
def slice!(*keys)
|
26
|
-
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
|
27
|
-
omit = slice(*self.keys - keys)
|
28
|
-
hash = slice(*keys)
|
29
|
-
hash.default = default
|
30
|
-
hash.default_proc = default_proc if default_proc
|
31
|
-
replace(hash)
|
32
|
-
omit
|
33
|
-
end
|
34
|
-
|
35
|
-
# Removes and returns the key/value pairs matching the given keys.
|
36
|
-
#
|
37
|
-
# { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2}
|
38
|
-
# { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
|
39
|
-
def extract!(*keys)
|
40
|
-
keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
|
41
|
-
end
|
42
|
-
end
|