diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5ce00b4..ececcb5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,7 +5,7 @@ jobs:
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
with:
engine: cruby
- min_version: 2.5
+ min_version: 3.1
test:
needs: ruby-versions
name: >-
@@ -21,9 +21,6 @@ jobs:
os: "ubuntu-latest"
TEST_SYMLINK: yes
rubyopt: "--enable-frozen-string-literal"
- exclude:
- - ruby-version: "2.5"
- os: "macos-latest"
runs-on: ${{ matrix.os }}
env:
TEST_SYMLINK: ${{ matrix.TEST_SYMLINK }}
diff --git a/Gemfile b/Gemfile
index 22399a2..992034e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,6 @@ group :development do
gem 'test-unit'
gem 'rake'
gem 'simplecov'
- gem 'bundler'
gem 'irb', '>= 1.3.1'
gem 'benchmark-ips'
end
diff --git a/README.md b/README.md
index 0ff93db..c461c08 100644
--- a/README.md
+++ b/README.md
@@ -24,11 +24,11 @@ Use following test frameworks or extensions instead.
* [power_p](https://github.com/k-tsj/power_p)
## Requirement
-* CRuby 2.5+
+* CRuby 3.1+
## Configuration
To colorize output messages, add require "power_assert/colorize" to your code.
-(It requires CRuby 3.0.1+ or irb 1.3.1+)
+(It requires irb 1.3.1+)
## Known Limitations
* Expressions must be put in one line. Expressions with folded long lines produce nothing report, e.g.:
@@ -61,23 +61,19 @@ assert do
end
```
-* Returned values from accessor methods, method missing, or "super" produce nothing report, e.g:
+* Returned values from method missing, or "super" produce nothing report, e.g:
```ruby
class Foo
- attr_accessor :val
+ def method_missing(*)
+ :foo
+ end
end
foo = Foo.new
-foo.val = false
-
-assert do
- # reported (only the value of "foo" and the literal "true")
- foo.val == true
-end
assert do
# won't be reported
- foo.val
+ foo.foo
end
```
diff --git a/Rakefile b/Rakefile
index e82d34c..1e86b31 100644
--- a/Rakefile
+++ b/Rakefile
@@ -8,7 +8,6 @@ Rake::TestTask.new(:test) do |t|
t.ruby_opts = ["-w", "-r#{helper_path}"]
t.test_files = FileList["test/**/*_test.rb"].exclude do |i|
begin
- next false unless defined?(RubyVM)
RubyVM::InstructionSequence.compile(File.read(i))
false
rescue SyntaxError
diff --git a/lib/power_assert.rb b/lib/power_assert.rb
index 785b19c..8de209e 100644
--- a/lib/power_assert.rb
+++ b/lib/power_assert.rb
@@ -28,9 +28,7 @@ module PowerAssert
class << self
def start(assertion_proc_or_source, assertion_method: nil, source_binding: TOPLEVEL_BINDING)
- if respond_to?(:clear_global_method_cache, true)
- clear_global_method_cache
- end
+ clear_global_method_cache
yield Context.new(assertion_proc_or_source, assertion_method, source_binding)
end
@@ -51,13 +49,11 @@ def internal_file?(file)
end
end
- if defined?(RubyVM)
- CLEAR_CACHE_ISEQ = RubyVM::InstructionSequence.compile('using PowerAssert.const_get(:Empty)')
- private_constant :CLEAR_CACHE_ISEQ
+ CLEAR_CACHE_ISEQ = RubyVM::InstructionSequence.compile('using PowerAssert.const_get(:Empty)')
+ private_constant :CLEAR_CACHE_ISEQ
- def clear_global_method_cache
- CLEAR_CACHE_ISEQ.eval
- end
+ def clear_global_method_cache
+ CLEAR_CACHE_ISEQ.eval
end
end
diff --git a/lib/power_assert/enable_tracepoint_events.rb b/lib/power_assert/enable_tracepoint_events.rb
index b0c4101..bdccd66 100644
--- a/lib/power_assert/enable_tracepoint_events.rb
+++ b/lib/power_assert/enable_tracepoint_events.rb
@@ -1,67 +1,53 @@
require 'power_assert/configuration'
-if defined?(RubyVM)
- if PowerAssert.configuration._redefinition
- module PowerAssert
- # set redefined flag
- basic_classes = [
- Integer, Float, String, Array, Hash, Symbol, Time, Regexp, NilClass, TrueClass, FalseClass
- ]
-
- verbose = $VERBOSE
- begin
- $VERBOSE = nil
- [:Fixnum, :Bignum].each do |c|
- if Object.const_defined?(c) and (c = Object.const_get(c)) != Integer
- basic_classes << c
+if PowerAssert.configuration._redefinition
+ module PowerAssert
+ # set redefined flag
+ basic_classes = [
+ Integer, Float, String, Array, Hash, Symbol, Time, Regexp, NilClass, TrueClass, FalseClass
+ ]
+
+ basic_operators = [
+ :+, :-, :*, :/, :%, :==, :===, :<, :<=, :<<, :[], :[]=, :length, :size,
+ :empty?, :nil?, :succ, :>, :>=, :!, :!=, :=~, :freeze, :-@, :max, :min,
+ # :call (it is just used for block call optimization)
+ :&, :|,
+ # :default (no specialized instruction for this)
+ :pack, :include?,
+ ]
+
+ basic_classes.each do |klass|
+ basic_operators.each do |bop|
+ if klass.public_method_defined?(bop)
+ refine(klass) do
+ define_method(bop) {}
end
end
- ensure
- $VERBOSE = verbose
end
+ end
- basic_operators = [
- :+, :-, :*, :/, :%, :==, :===, :<, :<=, :<<, :[], :[]=, :length, :size,
- :empty?, :nil?, :succ, :>, :>=, :!, :!=, :=~, :freeze, :-@, :max, :min,
- # :call (it is just used for block call optimization)
- :&, :|,
- # :default (no specialized instruction for this)
- :pack, :include?,
- ]
-
- basic_classes.each do |klass|
- basic_operators.each do |bop|
- if klass.public_method_defined?(bop)
- refine(klass) do
- define_method(bop) {}
- end
- end
- end
+ # bypass check_cfunc
+ refine BasicObject do
+ def !
end
- # bypass check_cfunc
- refine BasicObject do
- def !
- end
-
- def ==
- end
+ def ==
end
+ end
- refine Module do
- def ==
- end
+ refine Module do
+ def ==
end
+ end
- refine Class do
- def new
- end
+ refine Class do
+ def new
end
end
end
-
- # disable optimization
- RubyVM::InstructionSequence.compile_option = {
- specialized_instruction: false
- }
end
+
+# disable optimization
+RubyVM::InstructionSequence.compile_option = {
+ specialized_instruction: false
+}
diff --git a/lib/power_assert/parser.rb b/lib/power_assert/parser.rb
index ff67200..c8ad988 100644
--- a/lib/power_assert/parser.rb
+++ b/lib/power_assert/parser.rb
@@ -33,16 +33,13 @@ def method_id_set
private
def valid_syntax?(str)
- return true unless defined?(RubyVM)
- begin
- verbose, $VERBOSE = $VERBOSE, nil
- RubyVM::InstructionSequence.compile(str)
- true
- rescue SyntaxError
- false
- ensure
- $VERBOSE = verbose
- end
+ verbose, $VERBOSE = $VERBOSE, nil
+ RubyVM::InstructionSequence.compile(str)
+ true
+ rescue SyntaxError
+ false
+ ensure
+ $VERBOSE = verbose
end
def slice_expression(str)
@@ -68,113 +65,81 @@ class Branch < Array
# +--------+
#
def extract_idents(sexp)
- tag, * = sexp
- case tag
- when :arg_paren, :assoc_splat, :fcall, :hash, :method_add_block, :string_literal, :return
- extract_idents(sexp[1])
- when :assign, :massign
- extract_idents(sexp[2])
- when :opassign
- _, _, (_, op_name, (_, op_column)), s0 = sexp
- extract_idents(s0) + [Ident[:method, op_name.sub(/=\z/, ''), op_column]]
- when :dyna_symbol
- if sexp[1][0].kind_of?(Symbol)
- # sexp[1] can be [:string_content, [..]] while parsing { "a": 1 }
- extract_idents(sexp[1])
- else
- sexp[1].flat_map {|s| extract_idents(s) }
- end
- when :assoclist_from_args, :bare_assoc_hash, :paren, :string_embexpr,
- :regexp_literal, :xstring_literal
- sexp[1].flat_map {|s| extract_idents(s) }
- when :command
- [sexp[2], sexp[1]].flat_map {|s| extract_idents(s) }
- when :assoc_new, :dot2, :dot3, :string_content
- sexp[1..-1].flat_map {|s| extract_idents(s) }
- when :unary
- handle_columnless_ident([], sexp[1], extract_idents(sexp[2]))
- when :binary
- op = sexp[2]
- if AND_OR_OPS.include?(op)
- extract_idents(sexp[1]) + [Branch[extract_idents(sexp[3]), []]]
- else
- handle_columnless_ident(extract_idents(sexp[1]), op, extract_idents(sexp[3]))
- end
- when :call
- _, recv, (op_sym, op_name, _), method = sexp
+ case sexp
+ in [:arg_paren | :assoc_splat | :fcall | :hash | :method_add_block | :string_literal | :return, s, *]
+ extract_idents(s)
+ in [:assign | :massign, _, s]
+ extract_idents(s)
+ in [:opassign, _, [_, op_name, [_, op_column]], s]
+ extract_idents(s) + [Ident[:method, op_name.sub(/=\z/, ''), op_column]]
+ in [:dyna_symbol, [Symbol, *] => s]
+ # s can be [:string_content, [..]] while parsing an expression like { "a": 1 }
+ extract_idents(s)
+ in [:dyna_symbol, ss]
+ ss.flat_map {|s| extract_idents(s) }
+ in [:assoclist_from_args | :bare_assoc_hash | :paren | :string_embexpr | :regexp_literal | :xstring_literal, ss, *]
+ ss.flat_map {|s| extract_idents(s) }
+ in [:command, s0, s1]
+ [s1, s0].flat_map {|s| extract_idents(s) }
+ in [:assoc_new | :dot2 | :dot3 | :string_content, *ss]
+ ss.flat_map {|s| extract_idents(s) }
+ in [:unary, mid, s]
+ handle_columnless_ident([], mid, extract_idents(s))
+ in [:binary, s0, op, s1] if AND_OR_OPS.include?(op)
+ extract_idents(s0) + [Branch[extract_idents(s1), []]]
+ in [:binary, s0, op, s1]
+ handle_columnless_ident(extract_idents(s0), op, extract_idents(s1))
+ in [:call, recv, [op_sym, op_name, _], method]
with_safe_op = ((op_sym == :@op and op_name == '&.') or op_sym == :"&.")
if method == :call
handle_columnless_ident(extract_idents(recv), :call, [], with_safe_op)
else
extract_idents(recv) + (with_safe_op ? [Branch[extract_idents(method), []]] : extract_idents(method))
end
- when :array
- sexp[1] ? sexp[1].flat_map {|s| extract_idents(s) } : []
- when :command_call
- [sexp[1], sexp[4], sexp[3]].flat_map {|s| extract_idents(s) }
- when :aref
- handle_columnless_ident(extract_idents(sexp[1]), :[], extract_idents(sexp[2]))
- when :method_add_arg
- idents = extract_idents(sexp[1])
- if idents.empty?
- # idents may be empty(e.g. ->{}.())
- extract_idents(sexp[2])
- else
- if idents[-1].kind_of?(Branch) and idents[-1][1].empty?
- # Safe navigation operator is used. See :call clause also.
- idents[0..-2] + [Branch[extract_idents(sexp[2]) + idents[-1][0], []]]
- else
- idents[0..-2] + extract_idents(sexp[2]) + [idents[-1]]
- end
- end
- when :args_add_block
- _, (tag, ss0, *ss1), _ = sexp
- if tag == :args_add_star
- (ss0 + ss1).flat_map {|s| extract_idents(s) }
- else
- sexp[1].flat_map {|s| extract_idents(s) }
- end
- when :vcall
- _, (tag, name, (_, column)) = sexp
- if tag == :@ident
- [Ident[@proc_local_variables.include?(name) ? :ref : :method, name, column]]
- else
- []
- end
- when :program
- _, ((tag0, (tag1, (tag2, (tag3, mname, _)), _), (tag4, _, ss))) = sexp
- if tag0 == :method_add_block and tag1 == :method_add_arg and tag2 == :fcall and
- (tag3 == :@ident or tag3 == :@const) and mname == @assertion_method_name and (tag4 == :brace_block or tag4 == :do_block)
- ss.flat_map {|s| extract_idents(s) }
- else
- _, (s0, *) = sexp
- extract_idents(s0)
+ in [:array, ss]
+ ss ? ss.flat_map {|s| extract_idents(s) } : []
+ in [:command_call, s0, _, s1, s2]
+ [s0, s2, s1].flat_map {|s| extract_idents(s) }
+ in [:aref, s0, s1]
+ handle_columnless_ident(extract_idents(s0), :[], extract_idents(s1))
+ in [:method_add_arg, s0, s1]
+ case extract_idents(s0)
+ in []
+ # idents(s0) may be empty(e.g. ->{}.())
+ extract_idents(s1)
+ in [*is0, Branch[is1, []]]
+ # Safe navigation operator is used. See :call clause also.
+ is0 + [Branch[extract_idents(s1) + is1, []]]
+ in [*is, i]
+ is + extract_idents(s1) + [i]
end
- when :ifop
- _, s0, s1, s2 = sexp
+ in [:args_add_block, [:args_add_star, ss0, *ss1], _]
+ (ss0 + ss1).flat_map {|s| extract_idents(s) }
+ in [:args_add_block, ss, _]
+ ss.flat_map {|s| extract_idents(s) }
+ in [:vcall, [:@ident, name, [_, column]]]
+ [Ident[@proc_local_variables.include?(name) ? :ref : :method, name, column]]
+ in [:vcall, _]
+ []
+ in [:program, [[:method_add_block, [:method_add_arg, [:fcall, [:@ident | :@const, ^@assertion_method_name, _]], _], [:brace_block | :do_block, _, ss]]]]
+ ss.flat_map {|s| extract_idents(s) }
+ in [:program, [s, *]]
+ extract_idents(s)
+ in [:ifop, s0, s1, s2]
[*extract_idents(s0), Branch[extract_idents(s1), extract_idents(s2)]]
- when :if, :unless
- _, s0, ss0, (_, ss1) = sexp
- [*extract_idents(s0), Branch[ss0.flat_map {|s| extract_idents(s) }, ss1 ? ss1.flat_map {|s| extract_idents(s) } : []]]
- when :if_mod, :unless_mod
- _, s0, s1 = sexp
+ in [:if | :unless, s0, ss0, [_, ss1]]
+ [*extract_idents(s0), Branch[ss0.flat_map {|s| extract_idents(s) }, ss1.flat_map {|s| extract_idents(s) }]]
+ in [:if | :unless, s0, ss0, _]
+ [*extract_idents(s0), Branch[ss0.flat_map {|s| extract_idents(s) }, []]]
+ in [:if_mod | :unless_mod, s0, s1]
[*extract_idents(s0), Branch[extract_idents(s1), []]]
- when :var_ref, :var_field
- _, (tag, ref_name, (_, column)) = sexp
- case tag
- when :@kw
- if ref_name == 'self'
- [Ident[:ref, 'self', column]]
- else
- []
- end
- when :@ident, :@const, :@cvar, :@ivar, :@gvar
- [Ident[:ref, ref_name, column]]
- else
- []
- end
- when :@ident, :@const, :@op
- _, method_name, (_, column) = sexp
+ in [:var_ref | :var_field, [:@kw, 'self', [_, column]]]
+ [Ident[:ref, 'self', column]]
+ in [:var_ref | :var_field, [:@ident | :@const | :@cvar | :@ivar | :@gvar, ref_name, [_, column]]]
+ [Ident[:ref, ref_name, column]]
+ in [:var_ref | :var_field, _]
+ []
+ in [:@ident | :@const | :@op, method_name, [_, column]]
[Ident[:method, method_name, column]]
else
[]
diff --git a/test/block_test.rb b/test/block_test.rb
index 1d8e16a..8a83dc3 100644
--- a/test/block_test.rb
+++ b/test/block_test.rb
@@ -1,4 +1,4 @@
-if defined?(RubyVM) and ! RubyVM::InstructionSequence.compile_option[:specialized_instruction]
+if ! RubyVM::InstructionSequence.compile_option[:specialized_instruction]
warn "#{__FILE__}: specialized_instruction is set to false"
end
@@ -285,13 +285,7 @@ def inspect; '#'; end
end
t do
- older = <
-END
- newer = <'; end
| 0
#
END
- assert_includes [older, newer], assertion_message {
@obj.to_i.to_i.to_s
}
end
diff --git a/test/dyna_symbol_key_test.rb b/test/dyna_symbol_key_test.rb
index 6a21399..a855c3a 100644
--- a/test/dyna_symbol_key_test.rb
+++ b/test/dyna_symbol_key_test.rb
@@ -1,4 +1,4 @@
-if defined?(RubyVM) and ! RubyVM::InstructionSequence.compile_option[:specialized_instruction]
+if ! RubyVM::InstructionSequence.compile_option[:specialized_instruction]
warn "#{__FILE__}: specialized_instruction is set to false"
end
diff --git a/test/safe_op_test.rb b/test/safe_op_test.rb
index 0fc573a..dee3e95 100644
--- a/test/safe_op_test.rb
+++ b/test/safe_op_test.rb
@@ -1,4 +1,4 @@
-if defined?(RubyVM) and ! RubyVM::InstructionSequence.compile_option[:specialized_instruction]
+if ! RubyVM::InstructionSequence.compile_option[:specialized_instruction]
warn "#{__FILE__}: specialized_instruction is set to false"
end