midwire_common 1.1.1 → 2.0.0
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 +5 -5
- data/.github/mergeable.yml +43 -0
- data/.gitignore +23 -0
- data/.ruby-version +1 -1
- data/CLAUDE.md +95 -0
- data/Gemfile +2 -0
- data/README.md +8 -5
- data/Rakefile +3 -1
- data/docs/plans/2026-02-13-refinements-implementation.md +1494 -0
- data/docs/plans/2026-02-13-refinements-modernization-design.md +109 -0
- data/lib/midwire_common/all.rb +16 -1
- data/lib/midwire_common/array.rb +35 -45
- data/lib/midwire_common/data_file_cache.rb +6 -5
- data/lib/midwire_common/enumerable.rb +12 -8
- data/lib/midwire_common/file.rb +13 -1
- data/lib/midwire_common/float.rb +10 -3
- data/lib/midwire_common/hash.rb +94 -105
- data/lib/midwire_common/integer.rb +11 -0
- data/lib/midwire_common/number_behavior.rb +4 -2
- data/lib/midwire_common/rake_helper.rb +5 -3
- data/lib/midwire_common/rake_tasks.rb +2 -0
- data/lib/midwire_common/string.rb +76 -108
- data/lib/midwire_common/time.rb +10 -6
- data/lib/midwire_common/time_tool.rb +6 -2
- data/lib/midwire_common/version.rb +3 -1
- data/lib/midwire_common/yaml_setting.rb +4 -3
- data/lib/midwire_common.rb +8 -2
- data/lib/tasks/version.rake +21 -18
- data/midwire_common.gemspec +10 -13
- data/spec/lib/midwire_common/array_spec.rb +23 -23
- data/spec/lib/midwire_common/data_file_cache_spec.rb +14 -14
- data/spec/lib/midwire_common/enumerable_spec.rb +8 -4
- data/spec/lib/midwire_common/file/stat_spec.rb +8 -4
- data/spec/lib/midwire_common/float_spec.rb +7 -3
- data/spec/lib/midwire_common/hash_spec.rb +55 -24
- data/spec/lib/midwire_common/integer_spec.rb +11 -0
- data/spec/lib/midwire_common/rake_helper_spec.rb +6 -3
- data/spec/lib/midwire_common/string_spec.rb +46 -76
- data/spec/lib/midwire_common/time_spec.rb +19 -20
- data/spec/lib/midwire_common/time_tool_spec.rb +4 -2
- data/spec/lib/midwire_common/yaml_setting_spec.rb +8 -5
- data/spec/spec_helper.rb +18 -12
- metadata +29 -99
- data/Guardfile +0 -14
- data/lib/midwire_common/file/stat.rb +0 -11
- data/lib/midwire_common/fixnum.rb +0 -4
- data/spec/lib/midwire_common/fixnum_spec.rb +0 -15
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# midwire_common 2.0.0 — Refinements & Modernization Design
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
Replace all monkey-patching of Ruby core classes with **refinements**, modernize dependencies, bump minimum Ruby to 3.2, remove methods that overlap with stdlib, and release as version 2.0.0. Clean break — no backward compatibility layer.
|
|
6
|
+
|
|
7
|
+
## Approach: Refinements
|
|
8
|
+
|
|
9
|
+
Each monkey-patched file becomes a refinement module. Consumers opt in with `using`:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
using MidwireCommon::StringExtensions
|
|
13
|
+
"MyClass".snakerize # => "my_class"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or use `MidwireCommon::All` to activate everything:
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
using MidwireCommon::All
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Module Structure
|
|
23
|
+
|
|
24
|
+
| Current file | New module | Notes |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `string.rb` | `MidwireCommon::StringExtensions` | |
|
|
27
|
+
| `array.rb` | `MidwireCommon::ArrayExtensions` | |
|
|
28
|
+
| `hash.rb` | `MidwireCommon::HashExtensions` | |
|
|
29
|
+
| `float.rb` | `MidwireCommon::FloatExtensions` | |
|
|
30
|
+
| `fixnum.rb` | `MidwireCommon::IntegerExtensions` | Fixnum → Integer |
|
|
31
|
+
| `enumerable.rb` | `MidwireCommon::EnumerableExtensions` | |
|
|
32
|
+
| `time.rb` | `MidwireCommon::TimeExtensions` | |
|
|
33
|
+
| `file.rb` + `file/stat.rb` | `MidwireCommon::FileExtensions` | |
|
|
34
|
+
|
|
35
|
+
`NumberBehavior` stays as a module, included inside `refine` blocks for Float and Integer.
|
|
36
|
+
|
|
37
|
+
`BottomlessHash` moves under `MidwireCommon::BottomlessHash` namespace.
|
|
38
|
+
|
|
39
|
+
## Methods Removed (stdlib equivalents)
|
|
40
|
+
|
|
41
|
+
- `String#trim`, `#trim!`, `#left_trim`, `#left_trim!`, `#right_trim`, `#right_trim!` — use `strip`/`lstrip`/`rstrip`
|
|
42
|
+
- `Array#binsearch` — use `Array#bsearch` (built-in since Ruby 2.0)
|
|
43
|
+
- `Hash#except` — built into Ruby 3.0+
|
|
44
|
+
|
|
45
|
+
## Methods Kept (by module)
|
|
46
|
+
|
|
47
|
+
### StringExtensions
|
|
48
|
+
- `String.random` (class method)
|
|
49
|
+
- `#left_substr`, `#right_substr`
|
|
50
|
+
- `#here_with_pipe`
|
|
51
|
+
- `#alpha_numeric?`, `#email_address?`, `#zipcode?`, `#numeric?`
|
|
52
|
+
- `#format_phone`, `#sanitize`, `#sanitize!`, `#shorten`
|
|
53
|
+
- `#escape_single_quotes`, `#escape_double_quotes`
|
|
54
|
+
- `#snakerize`, `#camelize`
|
|
55
|
+
|
|
56
|
+
### ArrayExtensions
|
|
57
|
+
- `#count_occurrences`, `#randomize`, `#randomize!`
|
|
58
|
+
- `#sort_case_insensitive`
|
|
59
|
+
- `#each_with_first_last`
|
|
60
|
+
- `#superjoin`
|
|
61
|
+
|
|
62
|
+
### HashExtensions
|
|
63
|
+
- `#bottomless` (returns `MidwireCommon::BottomlessHash`)
|
|
64
|
+
- `#grep`, `#diff`, `#apply_diff`, `#apply_diff!`
|
|
65
|
+
- `#only`, `#pop`
|
|
66
|
+
- `#to_query_string` (fix: `URI.encode` → `URI.encode_www_form_component`)
|
|
67
|
+
- `#symbolize_keys`, `#symbolize_keys!`, `#recursively_symbolize_keys!`
|
|
68
|
+
|
|
69
|
+
### IntegerExtensions / FloatExtensions
|
|
70
|
+
- `#commify` (via `NumberBehavior`)
|
|
71
|
+
|
|
72
|
+
### EnumerableExtensions
|
|
73
|
+
- `#sort_by_frequency`
|
|
74
|
+
|
|
75
|
+
### TimeExtensions
|
|
76
|
+
- `Time.timestamp` (class method)
|
|
77
|
+
|
|
78
|
+
### FileExtensions
|
|
79
|
+
- `File::Stat.device_name` (class method)
|
|
80
|
+
|
|
81
|
+
## Utility Classes (unchanged, already namespaced)
|
|
82
|
+
- `MidwireCommon::DataFileCache`
|
|
83
|
+
- `MidwireCommon::YamlSetting`
|
|
84
|
+
- `MidwireCommon::TimeTool`
|
|
85
|
+
- `MidwireCommon::RakeHelper`
|
|
86
|
+
|
|
87
|
+
## Dependency Updates
|
|
88
|
+
|
|
89
|
+
| Gem | From | To |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `required_ruby_version` | `~> 2` | `>= 3.2` |
|
|
92
|
+
| `rspec` | `~> 2.14` | `~> 3.12` |
|
|
93
|
+
| `rake` | `~> 10.1` | `~> 13.0` |
|
|
94
|
+
| `rubocop` | `~> 0.36` | current |
|
|
95
|
+
| `simplecov` | `~> 0.7` | `~> 0.22` |
|
|
96
|
+
| `pry-nav` | `~> 0.2` | **removed** (use `debug` gem, built into Ruby 3.2+) |
|
|
97
|
+
| `guard`, `guard-*` | various | **removed** |
|
|
98
|
+
|
|
99
|
+
## Test Changes
|
|
100
|
+
|
|
101
|
+
- Update all specs to use refinements (`using MidwireCommon::StringExtensions` etc.)
|
|
102
|
+
- Add missing specs for `Hash#apply_diff` and `Hash#apply_diff!`
|
|
103
|
+
- Remove specs for deleted methods
|
|
104
|
+
- Rename `fixnum_spec.rb` → `integer_spec.rb`
|
|
105
|
+
- Remove Guardfile
|
|
106
|
+
|
|
107
|
+
## Version
|
|
108
|
+
|
|
109
|
+
2.0.0 — major bump signals breaking API change.
|
data/lib/midwire_common/all.rb
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'midwire_common/array'
|
|
2
4
|
require 'midwire_common/enumerable'
|
|
3
5
|
require 'midwire_common/data_file_cache'
|
|
4
6
|
require 'midwire_common/file'
|
|
5
|
-
require 'midwire_common/
|
|
7
|
+
require 'midwire_common/integer'
|
|
6
8
|
require 'midwire_common/float'
|
|
7
9
|
require 'midwire_common/hash'
|
|
8
10
|
require 'midwire_common/string'
|
|
9
11
|
require 'midwire_common/time'
|
|
10
12
|
require 'midwire_common/time_tool'
|
|
11
13
|
require 'midwire_common/yaml_setting'
|
|
14
|
+
|
|
15
|
+
module MidwireCommon
|
|
16
|
+
module All
|
|
17
|
+
include MidwireCommon::StringExtensions
|
|
18
|
+
include MidwireCommon::ArrayExtensions
|
|
19
|
+
include MidwireCommon::HashExtensions
|
|
20
|
+
include MidwireCommon::IntegerExtensions
|
|
21
|
+
include MidwireCommon::FloatExtensions
|
|
22
|
+
include MidwireCommon::EnumerableExtensions
|
|
23
|
+
include MidwireCommon::TimeExtensions
|
|
24
|
+
include MidwireCommon::FileExtensions
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/midwire_common/array.rb
CHANGED
|
@@ -1,54 +1,44 @@
|
|
|
1
|
-
#
|
|
2
|
-
class Array
|
|
3
|
-
def count_occurrences
|
|
4
|
-
hash = Hash.new(0)
|
|
5
|
-
each { |elem| hash[elem] += 1 }
|
|
6
|
-
hash
|
|
7
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
module MidwireCommon
|
|
4
|
+
module ArrayExtensions
|
|
5
|
+
refine Array do
|
|
6
|
+
def count_occurrences
|
|
7
|
+
hash = Hash.new(0)
|
|
8
|
+
each { |elem| hash[elem] += 1 }
|
|
9
|
+
hash
|
|
10
|
+
end
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
def randomize
|
|
13
|
+
sort_by { rand }
|
|
14
|
+
end
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
def randomize!
|
|
17
|
+
replace(randomize)
|
|
18
|
+
end
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
case ndx
|
|
24
|
-
when 0 then first_code.call(item)
|
|
25
|
-
when size - 1 then last_code.call(item)
|
|
26
|
-
else main_code.call(item)
|
|
20
|
+
def sort_case_insensitive
|
|
21
|
+
sort_by(&:downcase)
|
|
27
22
|
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
23
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
def each_with_first_last(first_code, main_code, last_code)
|
|
25
|
+
each_with_index do |item, ndx|
|
|
26
|
+
case ndx
|
|
27
|
+
when 0 then first_code.call(item)
|
|
28
|
+
when size - 1 then last_code.call(item)
|
|
29
|
+
else main_code.call(item)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
rest = ldescr[1..-1]
|
|
49
|
-
dim[0] + map do |arr|
|
|
50
|
-
(arr.respond_to?(:superjoin) && !rest.empty?) ? arr.superjoin(*rest) : arr.to_s
|
|
51
|
-
end.join(dim[1]) + dim[2]
|
|
34
|
+
# Make a string from a multi-dimensional array
|
|
35
|
+
def superjoin(*ldescr)
|
|
36
|
+
dim = ldescr[0]
|
|
37
|
+
rest = ldescr[1..]
|
|
38
|
+
dim[0] + map do |arr|
|
|
39
|
+
arr.respond_to?(:superjoin) && !rest.empty? ? arr.superjoin(*rest) : arr.to_s
|
|
40
|
+
end.join(dim[1]) + dim[2]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
52
43
|
end
|
|
53
|
-
# rubocop:enable Metrics/LineLength
|
|
54
44
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module MidwireCommon
|
|
2
4
|
# A simple class to cache data in a file
|
|
3
5
|
class DataFileCache
|
|
@@ -10,7 +12,7 @@ module MidwireCommon
|
|
|
10
12
|
def put(data)
|
|
11
13
|
newdata = data.dup
|
|
12
14
|
newdata = newdata.join("\n") if newdata.is_a? Array
|
|
13
|
-
File.
|
|
15
|
+
File.write(@cache_file, newdata)
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
def get
|
|
@@ -19,19 +21,18 @@ module MidwireCommon
|
|
|
19
21
|
|
|
20
22
|
def age
|
|
21
23
|
return 999_999_99.0 unless File.exist?(@cache_file)
|
|
24
|
+
|
|
22
25
|
(Time.now - File.ctime(@cache_file)).to_f
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
private
|
|
26
29
|
|
|
27
30
|
def ensure_cache_dir
|
|
28
|
-
FileUtils.mkdir_p(@cache_dir)
|
|
31
|
+
FileUtils.mkdir_p(@cache_dir)
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
def normalize_filename(filename)
|
|
32
|
-
unless filename.match(Regexp.new(@cache_dir))
|
|
33
|
-
filename = "#{@cache_dir}/#{filename}"
|
|
34
|
-
end
|
|
35
|
+
filename = "#{@cache_dir}/#{filename}" unless filename.match(Regexp.new(@cache_dir))
|
|
35
36
|
filename
|
|
36
37
|
end
|
|
37
38
|
end
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MidwireCommon
|
|
4
|
+
module EnumerableExtensions
|
|
5
|
+
refine Enumerable do
|
|
6
|
+
def sort_by_frequency
|
|
7
|
+
histogram = each_with_object(Hash.new(0)) do |elem, hash|
|
|
8
|
+
hash[elem] += 1
|
|
9
|
+
hash
|
|
10
|
+
end
|
|
11
|
+
sort_by { |elem| [histogram[elem] * -1, elem] }
|
|
12
|
+
end
|
|
8
13
|
end
|
|
9
|
-
sort_by { |elem| [histogram[elem] * -1, elem] }
|
|
10
14
|
end
|
|
11
15
|
end
|
data/lib/midwire_common/file.rb
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MidwireCommon
|
|
4
|
+
module FileExtensions
|
|
5
|
+
refine File::Stat.singleton_class do
|
|
6
|
+
def device_name(file)
|
|
7
|
+
Dir['/dev/*'].inject({}) do |hash, node|
|
|
8
|
+
hash.update(File.stat(node).rdev => node)
|
|
9
|
+
end.values_at(File.stat(file).dev).first || nil
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/midwire_common/float.rb
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'midwire_common'
|
|
4
|
+
|
|
5
|
+
module MidwireCommon
|
|
6
|
+
module FloatExtensions
|
|
7
|
+
refine Float do
|
|
8
|
+
import_methods MidwireCommon::NumberBehavior
|
|
9
|
+
end
|
|
10
|
+
end
|
|
4
11
|
end
|
data/lib/midwire_common/hash.rb
CHANGED
|
@@ -1,128 +1,117 @@
|
|
|
1
|
-
#
|
|
2
|
-
# http://firedev.com/posts/2015/bottomless-ruby-hash/
|
|
3
|
-
class BottomlessHash < Hash
|
|
4
|
-
def initialize
|
|
5
|
-
super(&-> (hash, key) { hash[key] = self.class.new })
|
|
6
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
new.merge(hash)
|
|
10
|
-
end
|
|
11
|
-
end
|
|
3
|
+
require 'uri'
|
|
12
4
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
5
|
+
module MidwireCommon
|
|
6
|
+
# By Nick Ostrovsky
|
|
7
|
+
# http://firedev.com/posts/2015/bottomless-ruby-hash/
|
|
8
|
+
class BottomlessHash < Hash
|
|
9
|
+
def self.from_hash(hash)
|
|
10
|
+
new.merge(hash)
|
|
11
|
+
end
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
each_with_object([]) do |kv, res|
|
|
22
|
-
res << kv if kv[0] =~ pattern || kv[1] =~ pattern
|
|
23
|
-
res
|
|
13
|
+
def initialize
|
|
14
|
+
super(&->(hash, key) { hash[key] = self.class.new })
|
|
24
15
|
end
|
|
16
|
+
|
|
25
17
|
end
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
memo[key] = if self[key].is_a?(Hash) && other[key].is_a?(Hash)
|
|
32
|
-
self[key].diff(other[key])
|
|
33
|
-
else
|
|
34
|
-
[self[key], other[key]]
|
|
35
|
-
end
|
|
19
|
+
module HashExtensions
|
|
20
|
+
refine Hash do
|
|
21
|
+
def bottomless
|
|
22
|
+
MidwireCommon::BottomlessHash.from_hash(self)
|
|
36
23
|
end
|
|
37
|
-
memo
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
# rubocop:enable Metrics/AbcSize
|
|
41
24
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
while local_changes
|
|
47
|
-
local_changes.each_pair do |key, change|
|
|
48
|
-
if change.is_a?(Array)
|
|
49
|
-
pos[key] = (direction == :right) ? change[1] : change[0]
|
|
50
|
-
else
|
|
51
|
-
path.push([pos[key], change])
|
|
25
|
+
def grep(pattern)
|
|
26
|
+
each_with_object([]) do |kv, res|
|
|
27
|
+
res << kv if kv[0] =~ pattern || kv[1] =~ pattern
|
|
28
|
+
res
|
|
52
29
|
end
|
|
53
30
|
end
|
|
54
|
-
pos, local_changes = path.pop
|
|
55
|
-
end
|
|
56
|
-
self
|
|
57
|
-
end
|
|
58
31
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
else
|
|
70
|
-
pos[key] = pos[key].clone
|
|
71
|
-
path.push([pos[key], change])
|
|
32
|
+
def diff(other)
|
|
33
|
+
(keys + other.keys).uniq.each_with_object({}) do |key, memo|
|
|
34
|
+
unless self[key] == other[key]
|
|
35
|
+
memo[key] = if self[key].is_a?(Hash) && other[key].is_a?(Hash)
|
|
36
|
+
self[key].diff(other[key])
|
|
37
|
+
else
|
|
38
|
+
[self[key], other[key]]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
memo
|
|
72
42
|
end
|
|
73
43
|
end
|
|
74
|
-
pos, local_changes = path.pop
|
|
75
|
-
end
|
|
76
|
-
cloned
|
|
77
|
-
end
|
|
78
|
-
# rubocop:enable Metrics/AbcSize
|
|
79
44
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
45
|
+
def apply_diff!(changes, direction = :right)
|
|
46
|
+
path = [[self, changes]]
|
|
47
|
+
pos, local_changes = path.pop
|
|
48
|
+
while local_changes
|
|
49
|
+
local_changes.each_pair do |key, change|
|
|
50
|
+
if change.is_a?(Array)
|
|
51
|
+
pos[key] = direction == :right ? change[1] : change[0]
|
|
52
|
+
else
|
|
53
|
+
path.push([pos[key], change])
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
pos, local_changes = path.pop
|
|
57
|
+
end
|
|
58
|
+
self
|
|
59
|
+
end
|
|
84
60
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
61
|
+
def apply_diff(changes, direction = :right)
|
|
62
|
+
cloned = clone
|
|
63
|
+
path = [[cloned, changes]]
|
|
64
|
+
pos, local_changes = path.pop
|
|
65
|
+
while local_changes
|
|
66
|
+
local_changes.each_pair do |key, change|
|
|
67
|
+
if change.is_a?(Array)
|
|
68
|
+
pos[key] = direction == :right ? change[1] : change[0]
|
|
69
|
+
else
|
|
70
|
+
pos[key] = pos[key].clone
|
|
71
|
+
path.push([pos[key], change])
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
pos, local_changes = path.pop
|
|
75
|
+
end
|
|
76
|
+
cloned
|
|
77
|
+
end
|
|
89
78
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
ret = reject { |key, _v| !keys.flatten.include?(key.to_sym) }
|
|
94
|
-
reject! { |key, _v| keys.flatten.include?(key.to_sym) }
|
|
95
|
-
ret
|
|
96
|
-
end
|
|
79
|
+
def only(*keys)
|
|
80
|
+
dup.select { |key, _v| keys.flatten.include?(key.to_sym) }
|
|
81
|
+
end
|
|
97
82
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
end.join('&')
|
|
104
|
-
end
|
|
83
|
+
def pop(*keys)
|
|
84
|
+
ret = reject { |key, _v| !keys.flatten.include?(key.to_sym) }
|
|
85
|
+
reject! { |key, _v| keys.flatten.include?(key.to_sym) }
|
|
86
|
+
ret
|
|
87
|
+
end
|
|
105
88
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
self[(key.to_sym rescue key) || key] = delete(key)
|
|
110
|
-
end
|
|
111
|
-
self
|
|
112
|
-
end
|
|
113
|
-
# rubocop:enable Style/RescueModifier
|
|
89
|
+
def to_query_string
|
|
90
|
+
URI.encode_www_form(self)
|
|
91
|
+
end
|
|
114
92
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
93
|
+
def symbolize_keys!
|
|
94
|
+
keys.each do |key|
|
|
95
|
+
self[begin
|
|
96
|
+
key.to_sym
|
|
97
|
+
rescue StandardError
|
|
98
|
+
key
|
|
99
|
+
end || key] = delete(key)
|
|
100
|
+
end
|
|
101
|
+
self
|
|
102
|
+
end
|
|
118
103
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
104
|
+
def symbolize_keys
|
|
105
|
+
dup.symbolize_keys!
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def recursively_symbolize_keys!
|
|
109
|
+
symbolize_keys!
|
|
110
|
+
values.each do |value|
|
|
111
|
+
value.recursively_symbolize_keys! if value.is_a?(Hash)
|
|
112
|
+
end
|
|
113
|
+
self
|
|
114
|
+
end
|
|
125
115
|
end
|
|
126
|
-
self
|
|
127
116
|
end
|
|
128
117
|
end
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module MidwireCommon
|
|
2
4
|
# Common number behavior
|
|
3
5
|
module NumberBehavior
|
|
4
6
|
# Format a number with commas and a decimal point
|
|
5
7
|
# rubocop:disable Style/PerlBackrefs
|
|
6
8
|
def commify
|
|
7
|
-
to_s =~ /([
|
|
9
|
+
to_s =~ /([^.]*)(\..*)?/
|
|
8
10
|
int = $1.reverse
|
|
9
|
-
dec = $2
|
|
11
|
+
dec = $2 || ''
|
|
10
12
|
while int.gsub!(/(,|\.|^)(\d{3})(\d)/, '\1\2,\3')
|
|
11
13
|
end
|
|
12
14
|
int.reverse + dec
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'midwire_common'
|
|
2
4
|
|
|
3
5
|
module MidwireCommon
|
|
@@ -5,20 +7,20 @@ module MidwireCommon
|
|
|
5
7
|
class RakeHelper
|
|
6
8
|
include Rake::DSL if defined? Rake::DSL
|
|
7
9
|
|
|
10
|
+
attr_reader :basedir
|
|
11
|
+
|
|
8
12
|
def self.install_tasks(opts = {})
|
|
9
13
|
dir = opts[:dir] || Dir.pwd
|
|
10
14
|
new(dir).install
|
|
11
15
|
end
|
|
12
16
|
|
|
13
|
-
attr_reader :basedir
|
|
14
|
-
|
|
15
17
|
def initialize(basedir)
|
|
16
18
|
@basedir = basedir
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def install
|
|
20
22
|
task_dir = File.expand_path('../tasks', File.dirname(__FILE__))
|
|
21
|
-
Dir["#{task_dir}/*.rake"].
|
|
23
|
+
Dir["#{task_dir}/*.rake"].each { |ext| load ext }
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
end
|