larrow-runner 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 556f8afefdbfa12b93f7c7f3029fcc5bf55b23f9
4
- data.tar.gz: 170901120bc4eeec5370639ae6bb00c33c6ebf14
3
+ metadata.gz: 649d405f97c00eba29947141c7c23f97da18b783
4
+ data.tar.gz: ab1fe09db103b64cb52fcc1003cf3ba3e4e0faa4
5
5
  SHA512:
6
- metadata.gz: 2b9e24d845add9b4f3e99cb968e5146541f2e8aa025fc20dc97df7aac5d2a85286e318fe10cec77c1dafdf02f95749280eefe55a1183fda70ccf016f8b105789
7
- data.tar.gz: 3597ae6bd3f599e1edb2b645fd9b752d46caf9a2b5c865303d1a7b8a10588e71e873b460e056dfca6d10349e8430e8485caecd2a2279dddcdbbd7bc95d11dff9
6
+ metadata.gz: 0ca859ab0d4d0f713a0a3e86d0340ca1b91d76e941acfe97e4318ead3e09fe9347d99f65118a357629be6a045edbc907e23ac9055da03c0eb10933765524dc23
7
+ data.tar.gz: f85aaf2b37ddfd2b8e0ef2daed67bbc591b3c8b75343efbf0b8f1c8105f30505d678e9b4dbcb8170fe3df1e887b55ee73d5a0c96ae3f46f8277519039163e8bc
data/README.md CHANGED
@@ -40,27 +40,26 @@ Congratulation! Now you can use larrow to help your develop works.
40
40
 
41
41
  ### testing
42
42
 
43
- unit test, integration test, system test, etc.)
43
+ Unit test, integration test, system test, etc.
44
44
  ```
45
45
  $ larrow go <source_url>
46
46
  ```
47
47
 
48
48
  ### application startup
49
49
 
50
- make a standalone application and start it(if necessary)
50
+ Make a standalone application and start it(if necessary)
51
51
  ```
52
52
  $ larrow build server <source_url>
53
53
  ```
54
54
 
55
55
  ### build image
56
56
 
57
- use image to speed-up your development
57
+ Use image to speed-up your development
58
58
 
59
59
  * build a image of your application
60
60
  ```
61
61
  $ larrow build image <source_url>
62
62
  ```
63
-
64
63
  * build a image from local LarrowFile
65
64
  ```
66
65
  $ larrow build image <larrow_file_path>
@@ -70,7 +69,7 @@ $ larrow build image <larrow_file_path>
70
69
 
71
70
  Larrow need to know how to setup/make/install/start... your application. So developer could write a `Larrow File` to declare these things.
72
71
 
73
- Larrow can be used as a CI worker like travis.
72
+ default larrow file: $source/.larrow.yml
74
73
  ## Contributing
75
74
 
76
75
  1. Fork it ( http://github.com/fsword/larrow-core/fork )
@@ -24,12 +24,9 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "simplecov", '~> 0.9'
25
25
  spec.add_development_dependency "parallel_tests", '~> 1.0'
26
26
 
27
- spec.add_runtime_dependency 'tilt', '~> 2'
28
27
  spec.add_runtime_dependency 'thor', '~> 0.19'
29
- spec.add_runtime_dependency "activesupport", "~> 4.1"
30
28
  spec.add_runtime_dependency "pry", '~> 0.10', '0.10.0'
31
29
  spec.add_runtime_dependency "pry-nav", '~> 0.2', '0.2.4'
32
- spec.add_runtime_dependency "minitest", '~> 5.4', '5.4.1'
33
30
 
34
31
  spec.add_runtime_dependency 'net-ssh', '~> 2.9'
35
32
  spec.add_runtime_dependency 'net-scp', '~> 1.2'
@@ -0,0 +1,7 @@
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
+ 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,20 @@
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
@@ -0,0 +1,38 @@
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
@@ -0,0 +1,15 @@
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
@@ -0,0 +1,23 @@
1
+ require 'active_support/hash_with_indifferent_access'
2
+
3
+ class Hash
4
+
5
+ # Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver:
6
+ #
7
+ # { a: 1 }.with_indifferent_access['a'] # => 1
8
+ def with_indifferent_access
9
+ ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
10
+ end
11
+
12
+ # Called when object is nested under an object that receives
13
+ # #with_indifferent_access. This method will be called on the current object
14
+ # by the enclosing object and is aliased to #with_indifferent_access by
15
+ # default. Subclasses of Hash may overwrite this method to return +self+ if
16
+ # converting to an <tt>ActiveSupport::HashWithIndifferentAccess</tt> would not be
17
+ # desirable.
18
+ #
19
+ # b = { b: 1 }
20
+ # { a: b }.with_indifferent_access['a'] # calls b.nested_under_indifferent_access
21
+ # # => {"b"=>32}
22
+ alias nested_under_indifferent_access with_indifferent_access
23
+ end
@@ -0,0 +1,162 @@
1
+ class Hash
2
+ # Returns a new hash with all keys converted using the block operation.
3
+ #
4
+ # hash = { name: 'Rob', age: '28' }
5
+ #
6
+ # hash.transform_keys{ |key| key.to_s.upcase }
7
+ # # => {"NAME"=>"Rob", "AGE"=>"28"}
8
+ def transform_keys
9
+ result = {}
10
+ each_key do |key|
11
+ result[yield(key)] = self[key]
12
+ end
13
+ result
14
+ end
15
+
16
+ # Destructively convert all keys using the block operations.
17
+ # Same as transform_keys but modifies +self+.
18
+ def transform_keys!
19
+ keys.each do |key|
20
+ self[yield(key)] = delete(key)
21
+ end
22
+ self
23
+ end
24
+
25
+ # Returns a new hash with all keys converted to strings.
26
+ #
27
+ # hash = { name: 'Rob', age: '28' }
28
+ #
29
+ # hash.stringify_keys
30
+ # # => { "name" => "Rob", "age" => "28" }
31
+ def stringify_keys
32
+ transform_keys{ |key| key.to_s }
33
+ end
34
+
35
+ # Destructively convert all keys to strings. Same as
36
+ # +stringify_keys+, but modifies +self+.
37
+ def stringify_keys!
38
+ transform_keys!{ |key| key.to_s }
39
+ end
40
+
41
+ # Returns a new hash with all keys converted to symbols, as long as
42
+ # they respond to +to_sym+.
43
+ #
44
+ # hash = { 'name' => 'Rob', 'age' => '28' }
45
+ #
46
+ # hash.symbolize_keys
47
+ # # => { name: "Rob", age: "28" }
48
+ def symbolize_keys
49
+ transform_keys{ |key| key.to_sym rescue key }
50
+ end
51
+ alias_method :to_options, :symbolize_keys
52
+
53
+ # Destructively convert all keys to symbols, as long as they respond
54
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
55
+ def symbolize_keys!
56
+ transform_keys!{ |key| key.to_sym rescue key }
57
+ end
58
+ alias_method :to_options!, :symbolize_keys!
59
+
60
+ # Validate all keys in a hash match <tt>*valid_keys</tt>, raising ArgumentError
61
+ # on a mismatch. Note that keys are NOT treated indifferently, meaning if you
62
+ # use strings for keys but assert symbols as keys, this will fail.
63
+ #
64
+ # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
65
+ # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
66
+ # { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
67
+ def assert_valid_keys(*valid_keys)
68
+ valid_keys.flatten!
69
+ each_key do |k|
70
+ unless valid_keys.include?(k)
71
+ raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
72
+ end
73
+ end
74
+ end
75
+
76
+ # Returns a new hash with all keys converted by the block operation.
77
+ # This includes the keys from the root hash and from all
78
+ # nested hashes and arrays.
79
+ #
80
+ # hash = { person: { name: 'Rob', age: '28' } }
81
+ #
82
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
83
+ # # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
84
+ def deep_transform_keys(&block)
85
+ _deep_transform_keys_in_object(self, &block)
86
+ end
87
+
88
+ # Destructively convert all keys by using the block operation.
89
+ # This includes the keys from the root hash and from all
90
+ # nested hashes and arrays.
91
+ def deep_transform_keys!(&block)
92
+ _deep_transform_keys_in_object!(self, &block)
93
+ end
94
+
95
+ # Returns a new hash with all keys converted to strings.
96
+ # This includes the keys from the root hash and from all
97
+ # nested hashes and arrays.
98
+ #
99
+ # hash = { person: { name: 'Rob', age: '28' } }
100
+ #
101
+ # hash.deep_stringify_keys
102
+ # # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
103
+ def deep_stringify_keys
104
+ deep_transform_keys{ |key| key.to_s }
105
+ end
106
+
107
+ # Destructively convert all keys to strings.
108
+ # This includes the keys from the root hash and from all
109
+ # nested hashes and arrays.
110
+ def deep_stringify_keys!
111
+ deep_transform_keys!{ |key| key.to_s }
112
+ end
113
+
114
+ # Returns a new hash with all keys converted to symbols, as long as
115
+ # they respond to +to_sym+. This includes the keys from the root hash
116
+ # and from all nested hashes and arrays.
117
+ #
118
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
119
+ #
120
+ # hash.deep_symbolize_keys
121
+ # # => {:person=>{:name=>"Rob", :age=>"28"}}
122
+ def deep_symbolize_keys
123
+ deep_transform_keys{ |key| key.to_sym rescue key }
124
+ end
125
+
126
+ # Destructively convert all keys to symbols, as long as they respond
127
+ # to +to_sym+. This includes the keys from the root hash and from all
128
+ # nested hashes and arrays.
129
+ def deep_symbolize_keys!
130
+ deep_transform_keys!{ |key| key.to_sym rescue key }
131
+ end
132
+
133
+ private
134
+ # support methods for deep transforming nested hashes and arrays
135
+ def _deep_transform_keys_in_object(object, &block)
136
+ case object
137
+ when Hash
138
+ object.each_with_object({}) do |(key, value), result|
139
+ result[yield(key)] = _deep_transform_keys_in_object(value, &block)
140
+ end
141
+ when Array
142
+ object.map {|e| _deep_transform_keys_in_object(e, &block) }
143
+ else
144
+ object
145
+ end
146
+ end
147
+
148
+ def _deep_transform_keys_in_object!(object, &block)
149
+ case object
150
+ when Hash
151
+ object.keys.each do |key|
152
+ value = object.delete(key)
153
+ object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
154
+ end
155
+ object
156
+ when Array
157
+ object.map! {|e| _deep_transform_keys_in_object!(e, &block)}
158
+ else
159
+ object
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,22 @@
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
@@ -0,0 +1,42 @@
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
@@ -0,0 +1,272 @@
1
+ require 'active_support/core_ext/hash/keys'
2
+
3
+ module ActiveSupport
4
+ # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
5
+ # to be the same.
6
+ #
7
+ # rgb = ActiveSupport::HashWithIndifferentAccess.new
8
+ #
9
+ # rgb[:black] = '#000000'
10
+ # rgb[:black] # => '#000000'
11
+ # rgb['black'] # => '#000000'
12
+ #
13
+ # rgb['white'] = '#FFFFFF'
14
+ # rgb[:white] # => '#FFFFFF'
15
+ # rgb['white'] # => '#FFFFFF'
16
+ #
17
+ # Internally symbols are mapped to strings when used as keys in the entire
18
+ # writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
19
+ # mapping belongs to the public interface. For example, given:
20
+ #
21
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
22
+ #
23
+ # You are guaranteed that the key is returned as a string:
24
+ #
25
+ # hash.keys # => ["a"]
26
+ #
27
+ # Technically other types of keys are accepted:
28
+ #
29
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
30
+ # hash[0] = 0
31
+ # hash # => {"a"=>1, 0=>0}
32
+ #
33
+ # but this class is intended for use cases where strings or symbols are the
34
+ # expected keys and it is convenient to understand both as the same. For
35
+ # example the +params+ hash in Ruby on Rails.
36
+ #
37
+ # Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
38
+ #
39
+ # rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
40
+ #
41
+ # which may be handy.
42
+ class HashWithIndifferentAccess < Hash
43
+ # Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
44
+ # this class.
45
+ def extractable_options?
46
+ true
47
+ end
48
+
49
+ def with_indifferent_access
50
+ dup
51
+ end
52
+
53
+ def nested_under_indifferent_access
54
+ self
55
+ end
56
+
57
+ def initialize(constructor = {})
58
+ if constructor.is_a?(Hash)
59
+ super()
60
+ update(constructor)
61
+ else
62
+ super(constructor)
63
+ end
64
+ end
65
+
66
+ def default(key = nil)
67
+ if key.is_a?(Symbol) && include?(key = key.to_s)
68
+ self[key]
69
+ else
70
+ super
71
+ end
72
+ end
73
+
74
+ def self.new_from_hash_copying_default(hash)
75
+ hash = hash.to_hash
76
+ new(hash).tap do |new_hash|
77
+ new_hash.default = hash.default
78
+ end
79
+ end
80
+
81
+ def self.[](*args)
82
+ new.merge!(Hash[*args])
83
+ end
84
+
85
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
86
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
87
+
88
+ # Assigns a new value to the hash:
89
+ #
90
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
91
+ # hash[:key] = 'value'
92
+ #
93
+ # This value can be later fetched using either +:key+ or +'key'+.
94
+ def []=(key, value)
95
+ regular_writer(convert_key(key), convert_value(value, for: :assignment))
96
+ end
97
+
98
+ alias_method :store, :[]=
99
+
100
+ # Updates the receiver in-place, merging in the hash passed as argument:
101
+ #
102
+ # hash_1 = ActiveSupport::HashWithIndifferentAccess.new
103
+ # hash_1[:key] = 'value'
104
+ #
105
+ # hash_2 = ActiveSupport::HashWithIndifferentAccess.new
106
+ # hash_2[:key] = 'New Value!'
107
+ #
108
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
109
+ #
110
+ # The argument can be either an
111
+ # <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
112
+ # In either case the merge respects the semantics of indifferent access.
113
+ #
114
+ # If the argument is a regular hash with keys +:key+ and +"key"+ only one
115
+ # of the values end up in the receiver, but which one is unspecified.
116
+ #
117
+ # When given a block, the value for duplicated keys will be determined
118
+ # by the result of invoking the block with the duplicated key, the value
119
+ # in the receiver, and the value in +other_hash+. The rules for duplicated
120
+ # keys follow the semantics of indifferent access:
121
+ #
122
+ # hash_1[:key] = 10
123
+ # hash_2['key'] = 12
124
+ # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
125
+ def update(other_hash)
126
+ if other_hash.is_a? HashWithIndifferentAccess
127
+ super(other_hash)
128
+ else
129
+ other_hash.to_hash.each_pair do |key, value|
130
+ if block_given? && key?(key)
131
+ value = yield(convert_key(key), self[key], value)
132
+ end
133
+ regular_writer(convert_key(key), convert_value(value))
134
+ end
135
+ self
136
+ end
137
+ end
138
+
139
+ alias_method :merge!, :update
140
+
141
+ # Checks the hash for a key matching the argument passed in:
142
+ #
143
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
144
+ # hash['key'] = 'value'
145
+ # hash.key?(:key) # => true
146
+ # hash.key?('key') # => true
147
+ def key?(key)
148
+ super(convert_key(key))
149
+ end
150
+
151
+ alias_method :include?, :key?
152
+ alias_method :has_key?, :key?
153
+ alias_method :member?, :key?
154
+
155
+ # Same as <tt>Hash#fetch</tt> where the key passed as argument can be
156
+ # either a string or a symbol:
157
+ #
158
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
159
+ # counters[:foo] = 1
160
+ #
161
+ # counters.fetch('foo') # => 1
162
+ # counters.fetch(:bar, 0) # => 0
163
+ # counters.fetch(:bar) { |key| 0 } # => 0
164
+ # counters.fetch(:zoo) # => KeyError: key not found: "zoo"
165
+ def fetch(key, *extras)
166
+ super(convert_key(key), *extras)
167
+ end
168
+
169
+ # Returns an array of the values at the specified indices:
170
+ #
171
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
172
+ # hash[:a] = 'x'
173
+ # hash[:b] = 'y'
174
+ # hash.values_at('a', 'b') # => ["x", "y"]
175
+ def values_at(*indices)
176
+ indices.collect { |key| self[convert_key(key)] }
177
+ end
178
+
179
+ # Returns an exact copy of the hash.
180
+ def dup
181
+ self.class.new(self).tap do |new_hash|
182
+ new_hash.default = default
183
+ end
184
+ end
185
+
186
+ # This method has the same semantics of +update+, except it does not
187
+ # modify the receiver but rather returns a new hash with indifferent
188
+ # access with the result of the merge.
189
+ def merge(hash, &block)
190
+ self.dup.update(hash, &block)
191
+ end
192
+
193
+ # Like +merge+ but the other way around: Merges the receiver into the
194
+ # argument and returns a new hash with indifferent access as result:
195
+ #
196
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
197
+ # hash['a'] = nil
198
+ # hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
199
+ def reverse_merge(other_hash)
200
+ super(self.class.new_from_hash_copying_default(other_hash))
201
+ end
202
+
203
+ # Same semantics as +reverse_merge+ but modifies the receiver in-place.
204
+ def reverse_merge!(other_hash)
205
+ replace(reverse_merge( other_hash ))
206
+ end
207
+
208
+ # Replaces the contents of this hash with other_hash.
209
+ #
210
+ # h = { "a" => 100, "b" => 200 }
211
+ # h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
212
+ def replace(other_hash)
213
+ super(self.class.new_from_hash_copying_default(other_hash))
214
+ end
215
+
216
+ # Removes the specified key from the hash.
217
+ def delete(key)
218
+ super(convert_key(key))
219
+ end
220
+
221
+ def stringify_keys!; self end
222
+ def deep_stringify_keys!; self end
223
+ def stringify_keys; dup end
224
+ def deep_stringify_keys; dup end
225
+ undef :symbolize_keys!
226
+ undef :deep_symbolize_keys!
227
+ def symbolize_keys; to_hash.symbolize_keys! end
228
+ def deep_symbolize_keys; to_hash.deep_symbolize_keys! end
229
+ def to_options!; self end
230
+
231
+ def select(*args, &block)
232
+ dup.tap { |hash| hash.select!(*args, &block) }
233
+ end
234
+
235
+ def reject(*args, &block)
236
+ dup.tap { |hash| hash.reject!(*args, &block) }
237
+ end
238
+
239
+ # Convert to a regular hash with string keys.
240
+ def to_hash
241
+ _new_hash= {}
242
+ each do |key, value|
243
+ _new_hash[convert_key(key)] = convert_value(value, for: :to_hash)
244
+ end
245
+ Hash.new(default).merge!(_new_hash)
246
+ end
247
+
248
+ protected
249
+ def convert_key(key)
250
+ key.kind_of?(Symbol) ? key.to_s : key
251
+ end
252
+
253
+ def convert_value(value, options = {})
254
+ if value.is_a? Hash
255
+ if options[:for] == :to_hash
256
+ value.to_hash
257
+ else
258
+ value.nested_under_indifferent_access
259
+ end
260
+ elsif value.is_a?(Array)
261
+ unless options[:for] == :assignment
262
+ value = value.dup
263
+ end
264
+ value.map! { |e| convert_value(e, options) }
265
+ else
266
+ value
267
+ end
268
+ end
269
+ end
270
+ end
271
+
272
+ HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess