diff --git a/lib/dekiru/data_migration_operator.rb b/lib/dekiru/data_migration_operator.rb index bbdfbd8..2869da5 100644 --- a/lib/dekiru/data_migration_operator.rb +++ b/lib/dekiru/data_migration_operator.rb @@ -53,11 +53,11 @@ def duration ((self.ended_at || Time.current) - self.started_at) end - def with_progress(enum, options = {}) + def each_with_progress(enum, options = {}) options = options.dup options[:total] ||= ((enum.size == Float::INFINITY ? nil : enum.size) rescue nil) options[:format] ||= options[:total] ? '%a |%b>>%i| %p%% %t' : '%a |%b>>%i| ??%% %t' - options[:output] ||= stream + options[:output] = stream @pb = ::ProgressBar.create(options) enum.each do |item| @@ -68,14 +68,9 @@ def with_progress(enum, options = {}) end def find_each_with_progress(target_scope, options = {}, &block) - enum = - if target_scope.is_a?(ActiveRecord::Batches) - target_scope.find_each - else - # ActiveRecord由来のfind_eachでないと思われる場合は明示的にenumeratorに変換 - target_scope.enum_for(:find_each) - end - with_progress(enum, options, &block) + # `LocalJumpError: no block given (yield)` が出る場合、 find_each メソッドが enumerator を返していない可能性があります + # 直接 each_with_progress を使うか、 find_each が enumerator を返すように修正してください + each_with_progress(target_scope.find_each, options, &block) end private diff --git a/spec/dekiru/data_migration_operator_spec.rb b/spec/dekiru/data_migration_operator_spec.rb index 59bc5e5..529385e 100644 --- a/spec/dekiru/data_migration_operator_spec.rb +++ b/spec/dekiru/data_migration_operator_spec.rb @@ -106,17 +106,38 @@ def flush end end - describe '#find_each_with_progress' do + describe '#each_with_progress' do + let(:record) { (0...10) } + it '進捗が表示される' do + allow(STDIN).to receive(:gets) do + "yes\n" + end + + sum = 0 + operator.execute do + each_with_progress(record, title: 'count up number') do |num| + sum += num + end + end + + expect(sum).to eq(45) + expect(operator.result).to eq(true) + expect(operator.error).to eq(nil) + expect(operator.stream.out).to include('Are you sure to commit?') + expect(operator.stream.out).to include('count up number:') + expect(operator.stream.out).to include('Finished successfully:') + expect(operator.stream.out).to include('Total time:') + end + + it 'total をオプションで渡すことができる' do class Dekiru::DummyRecord def self.count - 10 + raise "won't call" end - def self.find_each - (0...count).to_a.each do |num| - yield(num) - end + def self.each + yield 99 end end @@ -126,7 +147,36 @@ def self.find_each sum = 0 operator.execute do - find_each_with_progress(Dekiru::DummyRecord, title: 'count up number') do |num| + each_with_progress(Dekiru::DummyRecord, title: 'pass total as option', total: 1) do |num| + sum += num + end + end + + expect(sum).to eq(99) + expect(operator.result).to eq(true) + expect(operator.error).to eq(nil) + expect(operator.stream.out).to include('Are you sure to commit?') + expect(operator.stream.out).to include('pass total as option:') + expect(operator.stream.out).to include('Finished successfully:') + expect(operator.stream.out).to include('Total time:') + end + end + + describe '#find_each_with_progress' do + let(:record) do + (0...10).tap do |r| + r.singleton_class.alias_method(:find_each, :each) + end + end + + it '進捗が表示される' do + allow(STDIN).to receive(:gets) do + "yes\n" + end + + sum = 0 + operator.execute do + find_each_with_progress(record, title: 'count up number') do |num| sum += num end end @@ -147,7 +197,11 @@ def self.count end def self.find_each - yield 99 + if block_given? + yield 99 + else + Enumerator.new { |y| y << 99 } + end end end