zold 0.15.0 → 0.16.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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/bin/zold +9 -6
  4. data/features/gem_package.feature +1 -1
  5. data/features/step_definitions/steps.rb +2 -2
  6. data/fixtures/merge/into-no-wallet/assert.rb +1 -1
  7. data/fixtures/merge/random-expenses/assert.rb +1 -1
  8. data/fixtures/merge/simple-case/assert.rb +1 -1
  9. data/lib/zold/age.rb +16 -8
  10. data/lib/zold/amount.rb +4 -2
  11. data/lib/zold/cached_wallets.rb +5 -6
  12. data/lib/zold/commands/clean.rb +15 -8
  13. data/lib/zold/commands/diff.rb +3 -3
  14. data/lib/zold/commands/fetch.rb +4 -4
  15. data/lib/zold/commands/list.rb +5 -4
  16. data/lib/zold/commands/merge.rb +2 -1
  17. data/lib/zold/commands/node.rb +14 -12
  18. data/lib/zold/commands/propagate.rb +2 -2
  19. data/lib/zold/commands/push.rb +3 -3
  20. data/lib/zold/commands/remove.rb +4 -1
  21. data/lib/zold/commands/routines/reconnect.rb +1 -0
  22. data/lib/zold/copies.rb +13 -14
  23. data/lib/zold/dir_items.rb +44 -0
  24. data/lib/zold/head.rb +1 -1
  25. data/lib/zold/key.rb +2 -2
  26. data/lib/zold/log.rb +2 -0
  27. data/lib/zold/node/async_entrance.rb +38 -28
  28. data/lib/zold/node/entrance.rb +4 -11
  29. data/lib/zold/node/farm.rb +9 -9
  30. data/lib/zold/node/front.rb +40 -25
  31. data/lib/zold/node/nodup_entrance.rb +4 -4
  32. data/lib/zold/node/safe_entrance.rb +2 -2
  33. data/lib/zold/node/spread_entrance.rb +5 -9
  34. data/lib/zold/node/sync_entrance.rb +2 -23
  35. data/lib/zold/patch.rb +2 -2
  36. data/lib/zold/remotes.rb +10 -6
  37. data/lib/zold/sync_wallets.rb +3 -22
  38. data/lib/zold/tree_wallets.rb +11 -6
  39. data/lib/zold/txns.rb +1 -1
  40. data/lib/zold/version.rb +1 -1
  41. data/lib/zold/wallet.rb +14 -5
  42. data/lib/zold/wallets.rb +5 -4
  43. data/test/commands/routines/test_spread.rb +1 -1
  44. data/test/commands/test_alias.rb +4 -4
  45. data/test/commands/test_clean.rb +14 -1
  46. data/test/commands/test_create.rb +2 -2
  47. data/test/commands/test_diff.rb +5 -5
  48. data/test/commands/test_fetch.rb +2 -2
  49. data/test/commands/test_merge.rb +19 -19
  50. data/test/commands/test_node.rb +1 -1
  51. data/test/commands/test_pay.rb +7 -6
  52. data/test/commands/test_propagate.rb +2 -1
  53. data/test/commands/test_pull.rb +1 -1
  54. data/test/commands/test_push.rb +1 -1
  55. data/test/commands/test_remove.rb +57 -0
  56. data/test/commands/test_taxes.rb +1 -1
  57. data/test/fake_home.rb +11 -8
  58. data/test/node/fake_node.rb +2 -2
  59. data/test/node/test_async_entrance.rb +24 -8
  60. data/test/node/test_emission.rb +2 -2
  61. data/test/node/test_entrance.rb +8 -6
  62. data/test/node/test_farm.rb +1 -1
  63. data/test/node/test_front.rb +42 -33
  64. data/test/node/test_nodup_entrance.rb +2 -2
  65. data/test/node/test_safe_entrance.rb +5 -5
  66. data/test/node/test_spread_entrance.rb +3 -3
  67. data/test/node/test_sync_entrance.rb +1 -1
  68. data/test/test__helper.rb +3 -29
  69. data/test/test_cached_wallets.rb +1 -1
  70. data/test/test_copies.rb +4 -2
  71. data/test/test_dir_items.rb +88 -0
  72. data/test/test_key.rb +2 -2
  73. data/test/test_log.rb +38 -0
  74. data/test/test_patch.rb +11 -11
  75. data/test/test_prefixes.rb +1 -1
  76. data/test/test_remotes.rb +12 -6
  77. data/test/test_sync_wallets.rb +6 -6
  78. data/test/test_tax.rb +4 -4
  79. data/test/test_tree_wallets.rb +16 -2
  80. data/test/test_wallet.rb +26 -26
  81. data/test/test_wallets.rb +5 -2
  82. data/test/test_zold.rb +2 -2
  83. data/test/upgrades/test_protocol_up.rb +1 -1
  84. data/upgrades/move_wallets_into_tree.rb +1 -1
  85. data/upgrades/protocol_up.rb +3 -3
  86. data/upgrades/rename_foreign_wallets.rb +1 -1
  87. data/zold.gemspec +27 -25
  88. metadata +91 -56
@@ -54,13 +54,13 @@ module Zold
54
54
  raise 'Id can\'t be nil' if id.nil?
55
55
  raise 'Id must be of type Id' unless id.is_a?(Id)
56
56
  raise 'Body can\'t be nil' if body.nil?
57
- Tempfile.open(['', Wallet::EXTENSION]) do |f|
58
- File.write(f, body)
57
+ Tempfile.open(['', Wallet::EXT]) do |f|
58
+ IO.write(f, body)
59
59
  wallet = Wallet.new(f.path)
60
60
  wallet.refurbish
61
- after = File.read(wallet.path)
61
+ after = IO.read(wallet.path)
62
62
  before = @wallets.find(id) do |w|
63
- w.exists? ? File.read(w.path).to_s : ''
63
+ w.exists? ? IO.read(w.path).to_s : ''
64
64
  end
65
65
  if before == after
66
66
  @log.info(
@@ -58,8 +58,8 @@ module Zold
58
58
  raise 'Id can\'t be nil' if id.nil?
59
59
  raise 'Id must be of type Id' unless id.is_a?(Id)
60
60
  raise 'Body can\'t be nil' if body.nil?
61
- Tempfile.open(['', Wallet::EXTENSION]) do |f|
62
- File.write(f, body)
61
+ Tempfile.open(['', Wallet::EXT]) do |f|
62
+ IO.write(f, body)
63
63
  wallet = Wallet.new(f.path)
64
64
  wallet.refurbish
65
65
  unless wallet.protocol == Zold::PROTOCOL
@@ -21,6 +21,7 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  require 'concurrent'
24
+ require 'concurrent/set'
24
25
  require 'tempfile'
25
26
  require_relative 'emission'
26
27
  require_relative '../log'
@@ -40,17 +41,10 @@ module Zold
40
41
  # The entrance
41
42
  class SpreadEntrance
42
43
  def initialize(entrance, wallets, remotes, address, log: Log::Quiet.new, ignore_score_weakeness: false)
43
- raise 'Entrance can\'t be nil' if entrance.nil?
44
44
  @entrance = entrance
45
- raise 'Wallets can\'t be nil' if wallets.nil?
46
- raise 'Wallets must implement the contract of Wallets: method #find is required' unless wallets.respond_to?(:find)
47
45
  @wallets = wallets
48
- raise 'Remotes can\'t be nil' if remotes.nil?
49
- raise 'Remotes must be of type Remotes' unless remotes.is_a?(Remotes)
50
46
  @remotes = remotes
51
- raise 'Address can\'t be nil' if address.nil?
52
47
  @address = address
53
- raise 'Log can\'t be nil' if log.nil?
54
48
  @log = log
55
49
  @ignore_score_weakeness = ignore_score_weakeness
56
50
  end
@@ -64,7 +58,7 @@ module Zold
64
58
 
65
59
  def start
66
60
  @entrance.start do
67
- @seen = Set.new
61
+ @seen = Concurrent::Set.new
68
62
  @modified = Queue.new
69
63
  @push = Thread.start do
70
64
  Thread.current.abort_on_exception = true
@@ -95,13 +89,15 @@ module Zold
95
89
  end
96
90
  end
97
91
 
92
+ # This method is thread-safe
98
93
  def push(id, body)
99
94
  mods = @entrance.push(id, body)
95
+ return mods if @remotes.all.empty?
100
96
  (mods + [id]).each do |m|
101
97
  next if @seen.include?(m)
102
98
  @seen << m
103
99
  @modified.push(m)
104
- @log.debug("Push scheduled for #{m}, queue size is #{@modified.size}")
100
+ @log.debug("Spread-push scheduled for #{m}, queue size is #{@modified.size}")
105
101
  end
106
102
  mods
107
103
  end
@@ -21,6 +21,7 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  require 'concurrent'
24
+ require 'futex'
24
25
  require_relative '../log'
25
26
  require_relative '../id'
26
27
  require_relative '../verbose_thread'
@@ -33,12 +34,9 @@ module Zold
33
34
  # The entrance that makes sure only one thread works with a wallet
34
35
  class SyncEntrance
35
36
  def initialize(entrance, dir, timeout: 30, log: Log::Quiet.new)
36
- raise 'Entrance can\'t be nil' if entrance.nil?
37
37
  @entrance = entrance
38
- raise 'Dir can\'t be nil' if dir.nil?
39
38
  @dir = dir
40
39
  @timeout = timeout
41
- raise 'Log can\'t be nil' if log.nil?
42
40
  @log = log
43
41
  end
44
42
 
@@ -54,26 +52,7 @@ module Zold
54
52
 
55
53
  # Always returns an array with a single ID of the pushed wallet
56
54
  def push(id, body)
57
- f = File.join(@dir, "#{id}.lock")
58
- FileUtils.mkdir_p(File.dirname(f))
59
- File.open(f, File::RDWR | File::CREAT) do |lock|
60
- start = Time.now
61
- cycles = 0
62
- loop do
63
- break if lock.flock(File::LOCK_EX | File::LOCK_NB)
64
- sleep 0.1
65
- cycles += 1
66
- delay = Time.now - start
67
- if delay > @timeout
68
- raise "##{Process.pid}/#{Thread.current.name} can't get exclusive access to the wallet #{id}/e \
69
- because of the lock at #{lock.path}: #{File.read(lock)}"
70
- end
71
- if (cycles % 20).zero? && delay > 10
72
- @log.info("##{Process.pid}/#{Thread.current.name} still waiting for \
73
- exclusive access to #{id}/e, #{delay.round}s already")
74
- end
75
- end
76
- File.write(lock, "##{Process.pid}/#{Thread.current.name}/#{Time.now.utc.iso8601}")
55
+ Futex.new(File.join(@dir, id), log: @log).open do
77
56
  @entrance.push(id, body)
78
57
  end
79
58
  end
data/lib/zold/patch.rb CHANGED
@@ -119,7 +119,7 @@ among #{payer.txns.count} transactions: #{txn.to_text}")
119
119
  def save(file, overwrite: false)
120
120
  raise 'You have to join at least one wallet in' if @id.nil?
121
121
  before = ''
122
- before = File.read(file) if File.exist?(file)
122
+ before = IO.read(file) if File.exist?(file)
123
123
  wallet = Wallet.new(file)
124
124
  wallet.init(@id, @key, overwrite: overwrite, network: @network)
125
125
  File.open(file, 'a') do |f|
@@ -128,7 +128,7 @@ among #{payer.txns.count} transactions: #{txn.to_text}")
128
128
  end
129
129
  end
130
130
  wallet.refurbish
131
- after = File.read(file)
131
+ after = IO.read(file)
132
132
  before != after
133
133
  end
134
134
  end
data/lib/zold/remotes.rb CHANGED
@@ -25,6 +25,7 @@ require 'csv'
25
25
  require 'uri'
26
26
  require 'net/http'
27
27
  require 'time'
28
+ require 'futex'
28
29
  require 'fileutils'
29
30
  require 'backtrace'
30
31
  require_relative 'age'
@@ -52,10 +53,13 @@ module Zold
52
53
  attribute :file, Types::Strict::String
53
54
  attribute :network, Types::Strict::String.optional.default('test')
54
55
  attribute :timeout, Types::Strict::Integer.optional.default(16)
55
- attribute :mutex, Types::Object.optional.default(Mutex.new)
56
56
 
57
57
  # Empty, for standalone mode
58
- class Empty < Remotes
58
+ class Empty
59
+ def initialize
60
+ # Nothing to init here
61
+ end
62
+
59
63
  def all
60
64
  []
61
65
  end
@@ -131,7 +135,7 @@ module Zold
131
135
  end
132
136
 
133
137
  def defaults
134
- other = Remotes.new(file: File.join(File.dirname(__FILE__), '../../resources/remotes'))
138
+ other = Remotes.new(file: File.expand_path(File.join(File.dirname(__FILE__), '../../resources/remotes')))
135
139
  other.all.each do |r|
136
140
  add(r[:host], r[:port])
137
141
  end
@@ -220,13 +224,13 @@ module Zold
220
224
  end
221
225
 
222
226
  def mtime
223
- File.mtime(file)
227
+ File.exist?(file) ? File.mtime(file) : Time.now
224
228
  end
225
229
 
226
230
  private
227
231
 
228
232
  def modify
229
- mutex.synchronize do
233
+ Futex.new(file).open do
230
234
  save(yield(load))
231
235
  end
232
236
  end
@@ -261,7 +265,7 @@ module Zold
261
265
 
262
266
  def save(list)
263
267
  FileUtils.mkdir_p(File.dirname(file))
264
- File.write(
268
+ IO.write(
265
269
  file,
266
270
  list.uniq { |r| "#{r[:host]}:#{r[:port]}" }.map do |r|
267
271
  [
@@ -20,6 +20,7 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ require 'futex'
23
24
  require_relative 'log'
24
25
 
25
26
  # Sync collection of wallets.
@@ -29,9 +30,8 @@ require_relative 'log'
29
30
  module Zold
30
31
  # Synchronized collection of wallets
31
32
  class SyncWallets
32
- def initialize(wallets, dir = Dir.tmpdir, timeout: 30, log: Log::Quiet.new)
33
+ def initialize(wallets, timeout: 30, log: Log::Quiet.new)
33
34
  @wallets = wallets
34
- @dir = dir
35
35
  @log = log
36
36
  @timeout = timeout
37
37
  end
@@ -50,26 +50,7 @@ module Zold
50
50
 
51
51
  def find(id)
52
52
  @wallets.find(id) do |wallet|
53
- f = File.join(@dir, id)
54
- FileUtils.mkdir_p(File.dirname(f))
55
- File.open(f, File::RDWR | File::CREAT) do |lock|
56
- start = Time.now
57
- cycles = 0
58
- loop do
59
- break if lock.flock(File::LOCK_EX | File::LOCK_NB)
60
- sleep 0.1
61
- cycles += 1
62
- delay = (Time.now - start).round(2)
63
- if delay > @timeout
64
- raise "##{Process.pid}/#{Thread.current.name} can't get exclusive access to the wallet #{id} \
65
- because of the lock at #{lock.path}, after #{delay}s of waiting: #{File.read(lock)}"
66
- end
67
- if (cycles % 20).zero? && delay > 10
68
- @log.info("##{Process.pid}/#{Thread.current.name} still waiting for \
69
- exclusive access to #{id}, #{delay.round}s already: #{File.read(lock)}")
70
- end
71
- end
72
- File.write(lock, "##{Process.pid}/#{Thread.current.name}")
53
+ Futex.new(wallet.path, log: @log).open do
73
54
  yield wallet
74
55
  end
75
56
  end
@@ -22,6 +22,7 @@
22
22
  require 'pathname'
23
23
  require_relative 'id'
24
24
  require_relative 'wallet'
25
+ require_relative 'dir_items'
25
26
 
26
27
  # The local collection of wallets.
27
28
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -45,19 +46,23 @@ module Zold
45
46
 
46
47
  # Returns the list of their IDs (as plain text)
47
48
  def all
48
- Dir.glob("#{path}/**/*#{Wallet::EXTENSION}").select do |f|
49
- basename = File.basename(f, Wallet::EXTENSION)
50
- File.file?(f) &&
51
- !File.directory?(f) &&
49
+ DirItems.new(path).fetch.select do |f|
50
+ next unless f.end_with?(Wallet::EXT)
51
+ basename = File.basename(f, Wallet::EXT)
52
+ file = File.join(path, f)
53
+ File.file?(file) &&
54
+ !File.directory?(file) &&
52
55
  basename =~ /^[0-9a-fA-F]{16}$/ &&
53
56
  Id.new(basename).to_s == basename
54
- end.map { |w| Id.new(File.basename(w, Wallet::EXTENSION)) }
57
+ end.map { |w| Id.new(File.basename(w, Wallet::EXT)) }
55
58
  end
56
59
 
57
60
  def find(id)
58
61
  raise 'Id can\'t be nil' if id.nil?
59
62
  raise 'Id must be of type Id' unless id.is_a?(Id)
60
- yield Zold::Wallet.new(File.join(path, (id.to_s.split('', 5).take(4) + [id.to_s]).join('/')))
63
+ yield Wallet.new(
64
+ File.join(path, (id.to_s.split('', 5).take(4) + [id.to_s]).join('/') + Wallet::EXT)
65
+ )
61
66
  end
62
67
  end
63
68
  end
data/lib/zold/txns.rb CHANGED
@@ -39,7 +39,7 @@ module Zold
39
39
 
40
40
  def fetch
41
41
  raise "Wallet file '#{@file}' is absent" unless File.exist?(@file)
42
- lines = File.read(@file).split(/\n/)
42
+ lines = IO.read(@file).split(/\n/)
43
43
  raise "Not enough lines in #{@file}, just #{lines.count}" if lines.count < 4
44
44
  lines.drop(5)
45
45
  .each_with_index
data/lib/zold/version.rb CHANGED
@@ -25,6 +25,6 @@
25
25
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.15.0'
28
+ VERSION = '0.16.0'
29
29
  PROTOCOL = 2
30
30
  end
data/lib/zold/wallet.rb CHANGED
@@ -27,6 +27,7 @@ require_relative 'key'
27
27
  require_relative 'id'
28
28
  require_relative 'txn'
29
29
  require_relative 'tax'
30
+ require_relative 'copies'
30
31
  require_relative 'amount'
31
32
  require_relative 'hexnum'
32
33
  require_relative 'signature'
@@ -50,10 +51,13 @@ module Zold
50
51
  MAIN_NETWORK = 'zold'
51
52
 
52
53
  # The extension of the wallet files
53
- EXTENSION = '.z'
54
+ EXT = '.z'
54
55
 
55
56
  def initialize(file)
56
- @file = File.absolute_path(File.extname(file).empty? ? "#{file}#{EXTENSION}" : file)
57
+ unless file.end_with?(Wallet::EXT, Copies::EXT)
58
+ raise "Wallet file must end with #{Wallet::EXT} or #{Copies::EXT}: #{file}"
59
+ end
60
+ @file = File.absolute_path(file)
57
61
  @txns = Txns::Cached.new(Txns.new(@file))
58
62
  @head = Head::Cached.new(Head.new(@file))
59
63
  end
@@ -90,7 +94,7 @@ module Zold
90
94
  raise "File '#{@file}' already exists" if File.exist?(@file) && !overwrite
91
95
  raise "Invalid network name '#{network}'" unless network =~ /^[a-z]{4,16}$/
92
96
  FileUtils.mkdir_p(File.dirname(@file))
93
- File.write(@file, "#{network}\n#{PROTOCOL}\n#{id}\n#{pubkey.to_pub}\n\n")
97
+ IO.write(@file, "#{network}\n#{PROTOCOL}\n#{id}\n#{pubkey.to_pub}\n\n")
94
98
  @txns.flush
95
99
  @head.flush
96
100
  end
@@ -173,7 +177,7 @@ module Zold
173
177
  end
174
178
 
175
179
  def digest
176
- OpenSSL::Digest::SHA256.new(File.read(@file)).hexdigest
180
+ OpenSSL::Digest::SHA256.new(IO.read(@file)).hexdigest
177
181
  end
178
182
 
179
183
  # Age of wallet in hours
@@ -187,13 +191,18 @@ module Zold
187
191
  end
188
192
 
189
193
  def refurbish
190
- File.write(
194
+ IO.write(
191
195
  @file,
192
196
  "#{network}\n#{protocol}\n#{id}\n#{key.to_pub}\n\n#{txns.map { |t| t.to_s + "\n" }.join}"
193
197
  )
194
198
  @txns.flush
195
199
  end
196
200
 
201
+ def flush
202
+ @head.flush
203
+ @txns.flush
204
+ end
205
+
197
206
  private
198
207
 
199
208
  def max
data/lib/zold/wallets.rb CHANGED
@@ -22,6 +22,7 @@
22
22
  require 'pathname'
23
23
  require_relative 'id'
24
24
  require_relative 'wallet'
25
+ require_relative 'dir_items'
25
26
 
26
27
  # The local collection of wallets.
27
28
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -50,20 +51,20 @@ module Zold
50
51
 
51
52
  # Returns the list of their IDs (as plain text)
52
53
  def all
53
- Dir.new(path).select do |f|
54
+ DirItems.new(path).fetch(recursive: false).select do |f|
54
55
  file = File.join(@dir, f)
55
- basename = File.basename(f, Wallet::EXTENSION)
56
+ basename = File.basename(f, Wallet::EXT)
56
57
  File.file?(file) &&
57
58
  !File.directory?(file) &&
58
59
  basename =~ /^[0-9a-fA-F]{16}$/ &&
59
60
  Id.new(basename).to_s == basename
60
- end.map { |w| Id.new(File.basename(w, Wallet::EXTENSION)) }
61
+ end.map { |w| Id.new(File.basename(w, Wallet::EXT)) }
61
62
  end
62
63
 
63
64
  def find(id)
64
65
  raise 'Id can\'t be nil' if id.nil?
65
66
  raise "Id must be of type Id, #{id.class.name} instead" unless id.is_a?(Id)
66
- yield Zold::Wallet.new(File.join(path, id.to_s))
67
+ yield Wallet.new(File.join(path, id.to_s + Wallet::EXT))
67
68
  end
68
69
  end
69
70
  end
@@ -34,7 +34,7 @@ require_relative '../../../lib/zold/node/entrance.rb'
34
34
  # License:: MIT
35
35
  class TestSpread < Minitest::Test
36
36
  def test_spread_wallets
37
- FakeHome.new.run do |home|
37
+ FakeHome.new(log: test_log).run do |home|
38
38
  5.times { home.create_wallet }
39
39
  opts = {
40
40
  'routine-immediately' => true
@@ -11,7 +11,7 @@ class TestAlias < Minitest::Test
11
11
  # The syntax is already documented in the alias command in the help.
12
12
  def test_set_writes_alias_to_the_alias_file
13
13
  skip
14
- FakeHome.new.run do |home|
14
+ FakeHome.new(log: test_log).run do |home|
15
15
  wallet = home.create_wallet
16
16
  Zold::Alias.new(wallets: home.wallets, log: test_log).run(%W[set #{wallet.id} my-alias])
17
17
  assert_equal read_alias_file(home), %W[my-alias #{wallet.id}]
@@ -23,7 +23,7 @@ class TestAlias < Minitest::Test
23
23
  # The syntax is already documented in the alias command in the help.
24
24
  def test_remove_removes_the_alias_from_the_alias_file
25
25
  skip
26
- FakeHome.new.run do |home|
26
+ FakeHome.new(log: test_log).run do |home|
27
27
  wallet = home.create_wallet
28
28
  cmd = Zold::Alias.new(wallets: home.wallets, log: test_log)
29
29
  cmd.run(%W[set #{wallet.id} my-alias])
@@ -38,7 +38,7 @@ class TestAlias < Minitest::Test
38
38
  # The syntax is already documented in the alias command in the help.
39
39
  def test_show_prints_out_the_aliased_wallet_id
40
40
  skip
41
- FakeHome.new.run do |home|
41
+ FakeHome.new(log: test_log).run do |home|
42
42
  wallet = home.create_wallet
43
43
  cmd = Zold::Alias.new(wallets: home.wallets, log: test_log)
44
44
  cmd.run(%W[set #{wallet.id} my-alias])
@@ -51,6 +51,6 @@ class TestAlias < Minitest::Test
51
51
  private
52
52
 
53
53
  def read_alias_file(home)
54
- File.read(File.join(home.dir, 'aliases')).split(' ')
54
+ IO.read(File.join(home.dir, 'aliases')).split(' ')
55
55
  end
56
56
  end