diff --git a/README.md b/README.md index fec8350ef..8d1d28877 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ Debugging Misc edit Open a file or source location. - measure `measure` enables the mode to measure processing time. `measure :off` disables it. + measure `measure` enables the mode to measure processing time. `measure off` disables it. Context show_doc Look up documentation with RI. diff --git a/lib/irb/command/measure.rb b/lib/irb/command/measure.rb index f96be20de..5f72ab72a 100644 --- a/lib/irb/command/measure.rb +++ b/lib/irb/command/measure.rb @@ -3,42 +3,51 @@ module IRB module Command class Measure < Base - include RubyArgsExtractor - category "Misc" - description "`measure` enables the mode to measure processing time. `measure :off` disables it." - - def initialize(*args) - super(*args) - end + description "`measure` enables the mode to measure processing time. `measure off` disables it." def execute(arg) if arg&.match?(/^do$|^do[^\w]|^\{/) warn 'Configure IRB.conf[:MEASURE_PROC] to add custom measure methods.' return end - args, kwargs = ruby_args(arg) - execute_internal(*args, **kwargs) + + if arg.empty? + execute_internal(nil, nil) + elsif arg.start_with? ':' + # Legacy style `measure :stackprof`, `measure :off, :time` + type, arg_val = arg.split(/,\s*/, 2).map { |v| v.sub(/\A:/, '') } + warn "`measure #{arg}` is deprecated. Please use `measure #{[type, arg_val].compact.join(' ')}` instead." + execute_internal(type.to_sym, arg_val) + else + type, arg_val = arg.split(/\s+/, 2) + execute_internal(type.to_sym, arg_val) + end end - def execute_internal(type = nil, arg = nil) + def execute_internal(type, arg) # Please check IRB.init_config in lib/irb/init.rb that sets # IRB.conf[:MEASURE_PROC] to register default "measure" methods, - # "measure :time" (abbreviated as "measure") and "measure :stackprof". + # "measure time" (abbreviated as "measure") and "measure stackprof". case type when :off - IRB.unset_measure_callback(arg) + IRB.unset_measure_callback(arg&.to_sym) when :list IRB.conf[:MEASURE_CALLBACKS].each do |type_name, _, arg_val| puts "- #{type_name}" + (arg_val ? "(#{arg_val.inspect})" : '') end - when :on - added = IRB.set_measure_callback(arg) - puts "#{added[0]} is added." if added else - added = IRB.set_measure_callback(type, arg) - puts "#{added[0]} is added." if added + type, arg = arg&.to_sym, nil if type == :on + + measure_methods = IRB.conf[:MEASURE_PROC].keys.map(&:downcase) + if type && !measure_methods.include?(type) + puts "Measure method `#{type}` not found." + puts "Available measure methods: %w[#{measure_methods.join(' ')}]." + else + added = IRB.set_measure_callback(type&.to_sym, arg) + puts "#{added[0]} is added." if added + end end nil end diff --git a/lib/irb/init.rb b/lib/irb/init.rb index 7dc08912e..a13fa95c4 100644 --- a/lib/irb/init.rb +++ b/lib/irb/init.rb @@ -204,19 +204,9 @@ def IRB.set_measure_callback(type = nil, arg = nil, &block) added = [type_sym, IRB.conf[:MEASURE_PROC][type_sym], arg] end elsif IRB.conf[:MEASURE_PROC][:CUSTOM] - added = [:CUSTOM, IRB.conf[:MEASURE_PROC][:CUSTOM], arg] - elsif block_given? - added = [:BLOCK, block, arg] - found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] } - if found - found[1] = block - return added - else - IRB.conf[:MEASURE_CALLBACKS] << added - return added - end + added = [:CUSTOM, IRB.conf[:MEASURE_PROC][:CUSTOM], nil] else - added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME], arg] + added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME], nil] end if added IRB.conf[:MEASURE] = true diff --git a/test/irb/test_command.rb b/test/irb/test_command.rb index 567c3216c..93a8eb0bd 100644 --- a/test/irb/test_command.rb +++ b/test/irb/test_command.rb @@ -208,6 +208,13 @@ def test_irb_info_lang end class MeasureTest < CommandTestCase + CUSTOM_MEASURE_PROC = proc { |context, line, line_no, &block| + raise 'Wrong argument' unless IRB::Context === context && String === line && Integer === line_no + time = Time.now + result = block.() + puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE] + result + } def test_measure conf = { PROMPT: { @@ -225,11 +232,11 @@ def test_measure out, err = execute_lines( "measure\n", "3\n", - "measure :off\n", + "measure off\n", "3\n", - "measure :on\n", + "measure on\n", "3\n", - "measure :off\n", + "measure off\n", "3\n", conf: conf, main: c @@ -282,7 +289,7 @@ def test_measure_enabled_by_rc out, err = execute_lines( "3\n", - "measure :off\n", + "measure off\n", "3\n", conf: conf, ) @@ -292,12 +299,6 @@ def test_measure_enabled_by_rc end def test_measure_enabled_by_rc_with_custom - measuring_proc = proc { |line, line_no, &block| - time = Time.now - result = block.() - puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE] - result - } conf = { PROMPT: { DEFAULT: { @@ -308,12 +309,12 @@ def test_measure_enabled_by_rc_with_custom }, PROMPT_MODE: :DEFAULT, MEASURE: true, - MEASURE_PROC: { CUSTOM: measuring_proc } + MEASURE_PROC: { CUSTOM: CUSTOM_MEASURE_PROC } } out, err = execute_lines( "3\n", - "measure :off\n", + "measure off\n", "3\n", conf: conf, ) @@ -322,12 +323,6 @@ def test_measure_enabled_by_rc_with_custom end def test_measure_with_custom - measuring_proc = proc { |line, line_no, &block| - time = Time.now - result = block.() - puts 'custom processing time: %fs' % (Time.now - time) if IRB.conf[:MEASURE] - result - } conf = { PROMPT: { DEFAULT: { @@ -338,13 +333,13 @@ def test_measure_with_custom }, PROMPT_MODE: :DEFAULT, MEASURE: false, - MEASURE_PROC: { CUSTOM: measuring_proc } + MEASURE_PROC: { CUSTOM: CUSTOM_MEASURE_PROC } } out, err = execute_lines( "3\n", "measure\n", "3\n", - "measure :off\n", + "measure off\n", "3\n", conf: conf ) @@ -365,24 +360,24 @@ def test_measure_toggle PROMPT_MODE: :DEFAULT, MEASURE: false, MEASURE_PROC: { - FOO: proc { |&block| puts 'foo'; block.call }, - BAR: proc { |&block| puts 'bar'; block.call } + FOO: proc { |ctx, line, line_no, arg, &block| puts "foo(#{arg.inspect})"; block.call }, + BAR: proc { |ctx, line, line_no, arg, &block| puts "bar(#{arg.inspect})"; block.call } } } out, err = execute_lines( - "measure :foo\n", + "measure foo arg\n", "1\n", - "measure :on, :bar\n", + "measure on bar\n", "2\n", - "measure :off, :foo\n", + "measure off foo\n", "3\n", - "measure :off, :bar\n", + "measure off bar\n", "4\n", conf: conf ) assert_empty err - assert_match(/\AFOO is added\.\nfoo\n=> 1\nBAR is added\.\nbar\nfoo\n=> 2\nbar\n=> 3\n=> 4\n/, out) + assert_match(/\AFOO is added\.\nfoo\("arg"\)\n=> 1\nBAR is added\.\nbar\(nil\)\nfoo\("arg"\)\n=> 2\nbar\(nil\)\n=> 3\n=> 4\n/, out) end def test_measure_with_proc_warning @@ -410,6 +405,32 @@ def test_measure_with_proc_warning assert_match(/\A=> 3\n=> 3\n/, out) assert_empty(c.class_variables) end + + def test_legacy_measure_warning + conf = { + MEASURE_PROC: { + FOO: proc {}, + BAR: proc {}, + } + } + out, err = execute_lines( + "measure :foo\n", + "measure :on, :bar\n", + conf: conf + ) + assert_match(/FOO is added/, out) + assert_match(/BAR is added/, out) + assert_match(/`measure :foo` is deprecated. Please use `measure foo`/, err) + assert_match(/`measure :on, :bar` is deprecated. Please use `measure on bar`/, err) + end + + def test_unknown_method + out, err = execute_lines("measure foo\n", "measure on bar\n") + assert_empty(err) + assert_match(/`foo` not found/, out) + assert_match(/`bar` not found/, out) + assert_match(/time stackprof/, out) + end end class IrbSourceTest < CommandTestCase