larrow-runner 0.0.2 → 0.0.3
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.
- 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
|