jruby-lint 0.4.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -1
  3. data/README.md +2 -8
  4. data/jruby-lint.gemspec +2 -3
  5. data/lib/jruby/lint/ast.rb +1 -1
  6. data/lib/jruby/lint/checkers.rb +18 -1
  7. data/lib/jruby/lint/checkers/fork_exec.rb +22 -39
  8. data/lib/jruby/lint/checkers/gem.rb +44 -30
  9. data/lib/jruby/lint/checkers/gemspec.rb +4 -4
  10. data/lib/jruby/lint/checkers/nonatomic.rb +38 -8
  11. data/lib/jruby/lint/checkers/object_space.rb +8 -6
  12. data/lib/jruby/lint/checkers/system.rb +4 -4
  13. data/lib/jruby/lint/checkers/thread_critical.rb +4 -4
  14. data/lib/jruby/lint/cli.rb +8 -1
  15. data/lib/jruby/lint/collectors.rb +18 -7
  16. data/lib/jruby/lint/finding.rb +1 -1
  17. data/lib/jruby/lint/libraries.rb +21 -30
  18. data/lib/jruby/lint/project.rb +3 -3
  19. data/lib/jruby/lint/reporters/html.rb +4 -3
  20. data/lib/jruby/lint/reporters/jruby-lint.html.erb +10 -1
  21. data/lib/jruby/lint/reporters/text.rb +5 -4
  22. data/lib/jruby/lint/version.rb +1 -1
  23. data/spec/fixtures/C-Extension-Alternatives.md +81 -0
  24. data/spec/jruby/lint/ast_spec.rb +6 -6
  25. data/spec/jruby/lint/checkers_spec.rb +91 -62
  26. data/spec/jruby/lint/collectors_spec.rb +3 -9
  27. data/spec/jruby/lint/finding_spec.rb +10 -10
  28. data/spec/jruby/lint/libraries_spec.rb +13 -13
  29. data/spec/jruby/lint/project_spec.rb +34 -40
  30. data/spec/jruby/lint/reporters_spec.rb +22 -13
  31. data/spec/jruby/lint/version_spec.rb +1 -1
  32. data/spec/spec_helper.rb +1 -1
  33. metadata +30 -96
  34. data/lib/jruby/lint/checkers/timeout.rb +0 -21
  35. data/lib/jruby/lint/github.crt +0 -23
  36. data/spec/fixtures/C-Extension-Alternatives.html +0 -339
  37. data/spec/jruby/lint/cli_spec.rb +0 -73
@@ -38,6 +38,10 @@ module JRuby
38
38
  @options.ansi = true
39
39
  end
40
40
 
41
+ opts.on('--no-source-line', 'do not print out line of source') do
42
+ @options.no_src_line = true
43
+ end
44
+
41
45
  opts.on('--html [REPORT_FILE]', 'print report as html file') do |file|
42
46
  @options.html = file || 'jruby-lint.html'
43
47
  end
@@ -55,6 +59,9 @@ module JRuby
55
59
  end.parse!(args)
56
60
 
57
61
  @options.files = args.empty? ? nil : args
62
+ rescue OptionParser::InvalidOption
63
+ puts $!.message
64
+ exit -1
58
65
  end
59
66
 
60
67
  def run
@@ -71,7 +78,7 @@ module JRuby
71
78
  puts "OK"
72
79
  exit
73
80
  else
74
- puts "Found #{project.findings.size} items"
81
+ puts "Found #{project.findings.count { |e| !e.tags.include? "internal" } } items"
75
82
  exit 1
76
83
  end
77
84
  end
@@ -1,16 +1,25 @@
1
1
  module JRuby::Lint
2
2
  class Collector
3
- attr_accessor :checkers, :findings, :project, :contents, :file
3
+ attr_accessor :checkers, :findings, :project, :contents, :file, :stack
4
4
 
5
5
  def initialize(project = nil, file = nil)
6
6
  @checkers = Checker.loaded_checkers.map(&:new)
7
7
  @checkers.each {|c| c.collector = self }
8
8
  @findings = []
9
9
  @project, @file = project, file || '<inline-script>'
10
+
11
+ # top to bottom list of elements as they are visited
12
+ @stack = [] # FIXME: ast visiting is not something checkers can see so stored here for now
13
+ end
14
+
15
+ def add_finding(message, tags, line=nil)
16
+ src_line = line ? contents.split(/\n/)[line-1] : nil
17
+ @findings << Finding.new(message, tags, file, line, src_line)
10
18
  end
11
19
 
12
20
  class CheckersVisitor < AST::Visitor
13
- attr_reader :collector, :checkers
21
+ attr_reader :collector, :checkers, :stack
22
+
14
23
 
15
24
  def initialize(ast, collector, checkers)
16
25
  super(ast)
@@ -18,6 +27,7 @@ module JRuby::Lint
18
27
  end
19
28
 
20
29
  def visit(method, node)
30
+ @collector.stack.push node
21
31
  after_hooks = []
22
32
  checkers.each do |ch|
23
33
  begin
@@ -26,19 +36,20 @@ module JRuby::Lint
26
36
  after_hooks << res if res.respond_to?(:call)
27
37
  end
28
38
  rescue Exception => e
29
- collector.findings << Finding.new("Exception while traversing: #{e.message}\n at #{e.backtrace.first}",
30
- [:internal, :debug], node.position)
39
+ collector.add_finding("Exception while traversing: #{e.message}\n at #{e.backtrace.first}",
40
+ [:internal, :debug], node.line+1)
31
41
  end
32
42
  end
33
43
  super
34
44
  rescue Exception => e
35
- collector.findings << Finding.new("Exception while traversing: #{e.message}\n at #{e.backtrace.first}",
36
- [:internal, :debug], node.position)
45
+ collector.add_finding("Exception while traversing: #{e.message}\n at #{e.backtrace.first}",
46
+ [:internal, :debug], node.line+1)
37
47
  ensure
38
48
  begin
39
49
  after_hooks.each {|h| h.call }
40
50
  rescue
41
51
  end
52
+ @collector.stack.pop
42
53
  end
43
54
  end
44
55
 
@@ -47,7 +58,7 @@ module JRuby::Lint
47
58
  CheckersVisitor.new(ast, self, checkers).traverse
48
59
  rescue SyntaxError => e
49
60
  file, line, message = e.message.split(/:\s*/, 3)
50
- findings << Finding.new(message, [:syntax, :error], file, line)
61
+ add_finding(message, [:syntax, :error], line.to_i)
51
62
  end
52
63
  end
53
64
 
@@ -1,5 +1,5 @@
1
1
  module JRuby::Lint
2
- class Finding < Struct.new(:message, :tags, :file, :line)
2
+ class Finding < Struct.new(:message, :tags, :file, :line, :src_line)
3
3
  def initialize(*args)
4
4
  args[1].map! {|x| x.to_s } if args.size > 1
5
5
  if args.size > 2 && args[2].respond_to?(:file) && args[2].respond_to?(:line)
@@ -1,5 +1,4 @@
1
1
  require 'net/https'
2
- require 'nokogiri'
3
2
  require 'tempfile'
4
3
  require 'fileutils'
5
4
 
@@ -27,7 +26,7 @@ module JRuby::Lint
27
26
 
28
27
  def filename_for(name)
29
28
  name = File.basename(name)
30
- File.join(@cache_dir, File.extname(name).empty? ? "#{name}.html" : name)
29
+ File.join(@cache_dir, File.extname(name).empty? ? "#{name}.md" : name)
31
30
  end
32
31
 
33
32
  def stale?(filename)
@@ -35,28 +34,10 @@ module JRuby::Lint
35
34
  end
36
35
 
37
36
  def read_from_wiki(name, filename)
38
- content = nil
39
- uri = Net::HTTP.start('wiki.jruby.org', 80) do |http|
40
- URI.parse http.head(name =~ %r{^/} ? name : "/#{name}")['Location']
41
- end
42
- if uri.host == "github.com"
43
- Net::HTTP.new(uri.host, uri.port).tap do |http|
44
- if uri.scheme == "https"
45
- http.use_ssl = true
46
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
47
- # gd_bundle.crt from https://certs.godaddy.com/anonymous/repository.seam
48
- http.ca_file = File.expand_path('../github.crt', __FILE__)
49
- end
50
- http.start do
51
- response = http.get(uri.path)
52
- content = response.body
53
- File.open(filename, "w") do |f|
54
- f << content
55
- end
56
- end
57
- end
58
- end
59
- raise "Unknown location '#{uri}' for page '#{name}'" unless content
37
+ require 'open-uri'
38
+ download = open('https://github.com/jruby/jruby/wiki/C-Extension-Alternatives.md')
39
+ content = download.read(nil)
40
+ File.open(filename, "w") { |f| f << content }
60
41
  content
61
42
  rescue => e
62
43
  raise "Error while reading from wiki: #{e.message}\nPlease try again later."
@@ -72,11 +53,21 @@ module JRuby::Lint
72
53
 
73
54
  def load
74
55
  @gems = {}
75
- content = @cache.fetch('C-Extension-Alternatives')
76
- doc = Nokogiri::HTML(content)
77
- doc.css('#wiki-body ul li').each do |li|
78
- key, message = li.text.split(/[ -]+/, 2)
79
- @gems[key.downcase] = message
56
+ content = @cache.fetch('C-Extension-Alternatives.md')
57
+
58
+ in_suggestions = false
59
+ content.split("\n").each do |line|
60
+ if line =~ /<!-- suggestions start/
61
+ in_suggestions = true
62
+ elsif !in_suggestions
63
+ next
64
+ elsif line =~ /<!-- suggestions end/
65
+ in_suggestions = false
66
+ break
67
+ else
68
+ _, key, value = line.gsub(/[\[\]]/, '').split("|", 3)
69
+ @gems[key.downcase] = value
70
+ end
80
71
  end
81
72
  rescue => e
82
73
  @error = "Unable to load C Extension alternatives list: #{e.message}"
@@ -85,7 +76,7 @@ module JRuby::Lint
85
76
 
86
77
  SOURCES = [CExtensions]
87
78
 
88
- attr_reader :gems
79
+ attr_accessor :gems
89
80
 
90
81
  def initialize(cache)
91
82
  @sources = SOURCES.map {|s| s.new(cache) }
@@ -52,9 +52,9 @@ module JRuby::Lint
52
52
 
53
53
  def load_reporters(options)
54
54
  @reporters = []
55
- @reporters << Reporters::Html.new(self, options.html) if options.html
56
- @reporters << Reporters::ANSIColor.new(self, STDOUT) if options.ansi || STDOUT.tty?
57
- @reporters << Reporters::Text.new(self, STDOUT) if options.text || @reporters.empty?
55
+ @reporters << Reporters::Html.new(self, options.html, options) if options.html
56
+ @reporters << Reporters::ANSIColor.new(self, STDOUT, options) if options.ansi || STDOUT.tty?
57
+ @reporters << Reporters::Text.new(self, STDOUT, options) if options.text || @reporters.empty?
58
58
  end
59
59
 
60
60
  def load_libraries
@@ -1,11 +1,12 @@
1
+ require 'ostruct'
2
+
1
3
  module JRuby::Lint
2
4
  module Reporters
3
5
  class Html
4
6
  require 'erb'
5
7
 
6
- def initialize(project, output)
7
- @tags = project.tags
8
- @output = output
8
+ def initialize(project, output, options=OpenStruct.new)
9
+ @tags, @output, @options = project.tags, output, options
9
10
  @template = ERB.new(File.read(File.expand_path('../jruby-lint.html.erb', __FILE__)))
10
11
  end
11
12
 
@@ -29,10 +29,19 @@ nav { position: relative; }
29
29
  <% @findings.each do |finding| %>
30
30
  <% if finding.error? %>
31
31
  <li class="error"><%= finding %></li>
32
- <% elsif finding.warning? %>
32
+ <% if finding.src_line && !@options.no_src_line%>
33
+ <pre><%= finding.src_line %></pre>
34
+ <% end %>
35
+ <% elsif finding.warning? %>
33
36
  <li class="warning"><%= finding %></li>
37
+ <% if finding.src_line && !@options.no_src_line%>
38
+ <pre><%= finding.src_line %></pre>
39
+ <% end %>
34
40
  <% else %>
35
41
  <li class="message"><%= finding %></li>
42
+ <% if finding.src_line && !@options.no_src_line%>
43
+ <pre><%= finding.src_line %></pre>
44
+ <% end %>
36
45
  <% end %>
37
46
  <% end %>
38
47
  </ul>
@@ -1,8 +1,8 @@
1
1
  module JRuby::Lint
2
2
  module Reporters
3
3
  class Text
4
- def initialize(project, output)
5
- @tags, @output = project.tags, output
4
+ def initialize(project, output, options=OpenStruct.new)
5
+ @tags, @output, @options = project.tags, output, options
6
6
  end
7
7
 
8
8
  def report(findings)
@@ -23,11 +23,12 @@ module JRuby::Lint
23
23
  msg = if finding.error?
24
24
  red(finding.to_s)
25
25
  elsif finding.warning?
26
- yellow(finding.to_s)
26
+ cyan(finding.to_s)
27
27
  else
28
- finding.to_s
28
+ blue(finding.to_s)
29
29
  end
30
30
  @output.puts msg
31
+ @output.puts finding.src_line if finding.src_line && !@options.no_src_line
31
32
  end
32
33
  end
33
34
  end
@@ -1,5 +1,5 @@
1
1
  module JRuby
2
2
  module Lint
3
- VERSION = "0.4.1"
3
+ VERSION = "0.9.0"
4
4
  end
5
5
  end
@@ -0,0 +1,81 @@
1
+ JRuby does not support native C extensions, but it does have it's own Java native extensions API. Several gems have implementations of both Java and C extensions rolled into the same gem and those will not be listed here since they will just work. In some cases there is a JRuby version with a slightly different name or possibly even a totally different name and we list these here so you can update your Gemfile:
2
+
3
+ ```ruby
4
+ gem 'therubyracer', platform: :mri
5
+ gem 'therubyrhino', platform: :jruby
6
+ ```
7
+
8
+ When there is not an exact match some gems come close enough where a little work on your part can make your application compatible with JRuby.
9
+
10
+ This page lists common C extensions and JRuby-friendly alternatives you can use to replace them.
11
+
12
+ If you are interested in helping us port an extension to JRuby, this article is helpful: [Your first Ruby native extension: Java](https://blog.jcoglan.com/2012/08/02/your-first-ruby-native-extension-java/) see also [JRuby examples](https://github.com/jruby/jruby-examples) for a maven build.
13
+
14
+ <!-- suggestions start -->
15
+ | Gem | Suggestions |
16
+ |-----|-------------|
17
+ |[RDiscount][]|Use [kramdown][], [Maruku][] (pure Ruby) or [markdown_j][] (wrapper around a Java library)|
18
+ |[RedCarpet][]|Same as with **RDiscount** use alternatives such as [kramdown][], [Maruku][] or [markdown_j][]|
19
+ |[RMagick][]|Try [RMagick4J][] (implements ImageMagick functionality in Java) or preferably use alternatives [mini_magick][] & [quick_magick][]. For simple resizing, cropping, greyscaling, etc look at [image_voodoo][]. You can also use Java's Graphics2D.|
20
+ |[Unicorn][]| Use [Puma][].|
21
+ |[Thin][]| Use [Puma][].|
22
+ |mysql|Use [activerecord-jdbcmysql-adapter][].|
23
+ |mysql2|Use [activerecord-jdbcmysql-adapter][].|
24
+ |sqlite3|Use [activerecord-jdbcsqlite3-adapter][].|
25
+ |pg|Use [activerecord-jdbcpostgresql-adapter][] instead or [pg_jruby][] (drop-in replacement).|
26
+ |[yajl-ruby][]|Try `json` or `json_pure` instead. Unfortunately there is no known equivalent JSON stream parser.|
27
+ |[oj][]|Try `gson`, `json` or `json_pure` instead.|
28
+ |[bson_ext][]|`bson_ext` isn't used with JRuby. Instead, some native Java extensions are bundled with the `bson` gem.|
29
+ |[win32ole][]|Use the `jruby-win32ole` gem (preinstalled in JRuby's Windows installer).|
30
+ |[curb][]|[Rurl][] is an example how to implement _some_ of curb's functionality using [Apache HttpClient][]|
31
+ |[therubyracer][]|Try using [therubyrhino][] instead (or [dienashorner][] on Java 8+).|
32
+ |[kyotocabinet][]|Try using [kyotocabinet-java][] instead. This isn't 100% complete yet, but it covers most of the API.|
33
+ |[memcached][]|Try using [jruby-memcached][] instead. Alternatively you can use [jruby-ehcache][], a JRuby interface to Java's (JSR-107 compliant) Ehcache.|
34
+ |[charlock_holmes][]|Use [charlock_holmes-jruby][] instead.|
35
+ <!-- suggestions end -->
36
+
37
+ Please add to this list with your findings.
38
+
39
+ *Note that the [JRuby-Lint][] gem parses the contents of the list above to use for its Ruby gem checker. In order for JRuby-Lint to use the information, please adhere to the table format above and the links to projects below (in the source for this page).
40
+
41
+ <!-- links start -->
42
+ [RDiscount]: http://dafoster.net/projects/rdiscount/
43
+ [RedCarpet]: https://github.com/vmg/redcarpet
44
+ [kramdown]: https://github.com/gettalong/kramdown
45
+ [Maruku]:https://github.com/bhollis/maruku
46
+ [markdown_j]: https://github.com/nate/markdown_j
47
+ [RMagick]: https://github.com/rmagick/rmagick
48
+ [RMagick4J]: https://github.com/Serabe/RMagick4J
49
+ [mini_magick]: https://github.com/minimagick/minimagick
50
+ [quick_magick]: https://github.com/aseldawy/quick_magick
51
+ [image_voodoo]: https://github.com/jruby/image_voodoo
52
+ [Unicorn]: http://unicorn.bogomips.org/
53
+ [Puma]: http://puma.io/
54
+ [Thin]: http://code.macournoyer.com/thin/
55
+ [Typhoeus]: https://github.com/dbalatero/typhoeus
56
+ [activerecord-jdbc-adapter]: https://github.com/jruby/activerecord-jdbc-adapter
57
+ [JRuby-Lint]: https://github.com/jruby/jruby-lint
58
+ [Nokogiri]: http://nokogiri.org/
59
+ [yajl-ruby]: https://github.com/brianmario/yajl-ruby
60
+ [bson_ext]: https://github.com/mongodb/mongo-ruby-driver
61
+ [Apache HttpClient]: http://hc.apache.org/httpcomponents-client-ga/
62
+ [HttpURLConnection]: http://download.oracle.com/javase/1,5.0/docs/api/java/net/HttpURLConnection.html
63
+ [win32ole]: http://www.ruby-doc.org/stdlib/libdoc/win32ole/rdoc/index.html
64
+ [Rurl]: https://github.com/rcyrus/Rurl
65
+ [curb]: https://github.com/taf2/curb
66
+ [therubyracer]: https://github.com/cowboyd/therubyracer
67
+ [therubyrhino]: https://github.com/cowboyd/therubyrhino
68
+ [dienashorner]: https://github.com/kares/dienashorner
69
+ [kyotocabinet]: http://fallabs.com/kyotocabinet/
70
+ [kyotocabinet-java]: https://github.com/csw/kyotocabinet-java
71
+ [memcached]: https://github.com/evan/memcached
72
+ [jruby-memcached]: https://github.com/aurorafeint/jruby-memcached
73
+ [jruby-ehcache]: https://github.com/dylanz/ehcache
74
+ [oj]: https://github.com/ohler55/oj
75
+ [activerecord-jdbcmysql-adapter]: https://rubygems.org/gems/activerecord-jdbcmysql-adapter
76
+ [activerecord-jdbcsqlite3-adapter]: https://rubygems.org/gems/activerecord-jdbcsqlite3-adapter
77
+ [activerecord-jdbcpostgresql-adapter]: https://rubygems.org/gems/activerecord-jdbcpostgresql-adapter
78
+ [pg_jruby]: https://rubygems.org/gems/pg_jruby
79
+ [charlock_holmes]: https://github.com/brianmario/charlock_holmes
80
+ [charlock_holmes-jruby]: https://github.com/siuying/charlock_holmes-jruby
81
+ <!-- links start -->
@@ -5,19 +5,19 @@ describe JRuby::Lint::AST::Visitor do
5
5
  Given(:visitor) { JRuby::Lint::AST::Visitor.new(ast) }
6
6
 
7
7
  # RootNode
8
- # NewlineNode
9
- # FCallOneArgNode |puts|
10
- # ArrayNode
11
- # StrNode =="hello"
8
+ # FCallOneArgNode |puts|
9
+ # ArrayNode
10
+ # StrNode =="hello"
12
11
  Given(:script) { %{puts "hello"} }
13
12
 
14
13
  context "visits all nodes" do
15
14
  When { visitor.each_node { @count ||= 0; @count += 1} }
16
- Then { @count.should == 5 }
15
+ Then { expect(@count).to eq(4) }
17
16
  end
18
17
 
19
18
  context "selects nodes" do
20
19
  When { @nodes = visitor.select {|n| n.node_type == org.jruby.ast.NodeType::STRNODE } }
21
- Then { @nodes.size.should == 1 && @nodes.first.value.to_s.should == "hello" }
20
+ Then { expect(@nodes.size).to(eq(1)) &&
21
+ expect(@nodes.first.value.to_s).to(eq("hello")) }
22
22
  end
23
23
  end
@@ -5,14 +5,14 @@ describe JRuby::Lint::Checker do
5
5
  subject { Class.new { include JRuby::Lint::Checker } }
6
6
 
7
7
  it "finds all loaded checkers" do
8
- JRuby::Lint::Checker.loaded_checkers.should include(subject)
8
+ expect(JRuby::Lint::Checker.loaded_checkers).to include(subject)
9
9
  end
10
10
  end
11
11
  end
12
12
 
13
13
  describe JRuby::Lint::Checkers do
14
14
  Given(:gems) { { "rdiscount" => "may not work", "bson_ext" => "not needed" } }
15
- Given(:project) { double("project").tap {|p| p.stub_chain("libraries.gems") { gems } } }
15
+ Given(:project) {JRuby::Lint::Project.new.tap {|p| p.libraries.gems = gems }}
16
16
  Given(:collector) do
17
17
  JRuby::Lint::Collector.new(project).tap do |c|
18
18
  c.contents = script
@@ -26,16 +26,16 @@ describe JRuby::Lint::Checkers do
26
26
 
27
27
  context "detects fcall-style" do
28
28
  # FCallNoArgBlockNode |fork|
29
- Given(:script) { "fork { }; exec('cmd')" }
29
+ Given(:script) { "fork { }" }
30
30
  When { collector.run }
31
- Then { collector.findings.size.should == 2 }
31
+ Then { expect(collector.findings.size).to eq(1) }
32
32
  end
33
33
 
34
34
  context "detects vcall-style" do
35
35
  # VCallNode |fork|
36
36
  Given(:script) { "fork" }
37
37
  When { collector.run }
38
- Then { collector.findings.size.should == 1 }
38
+ Then { expect(collector.findings.size).to eq(1) }
39
39
  end
40
40
 
41
41
  context "does not detect call-style" do
@@ -43,15 +43,15 @@ describe JRuby::Lint::Checkers do
43
43
  # VCallNode |fork|
44
44
  Given(:script) { "fork.fork" }
45
45
  When { collector.run }
46
- Then { collector.findings.size.should == 0 }
46
+ Then { expect(collector.findings.size).to eq(0) }
47
47
  end
48
48
 
49
49
  context "detects Kernel::fork style" do
50
50
  # CallNoArgNode |fork|
51
51
  # ConstNode |Kernel|
52
- Given(:script) { "Kernel::fork; Kernel::exec('cmd')" }
52
+ Given(:script) { "Kernel::fork" }
53
53
  When { collector.run }
54
- Then { collector.findings.size.should == 2 }
54
+ Then { expect(collector.findings.size).to eq(1) }
55
55
  end
56
56
  end
57
57
 
@@ -61,25 +61,43 @@ describe JRuby::Lint::Checkers do
61
61
  context "creates a finding for a gem mentioned in the libraries" do
62
62
  Given(:script) { "gem 'rdiscount'" }
63
63
  When { collector.run }
64
- Then { collector.findings.size.should == 2 }
64
+ Then { expect(collector.findings.size).to eq(2) }
65
65
  end
66
66
 
67
67
  context "creates one finding to mention the wiki for gem compatibility" do
68
68
  Given(:script) { "gem 'rdiscount'; gem 'bson_ext'" }
69
69
  When { collector.run }
70
- Then { collector.findings.size.should == 3 }
70
+ Then { expect(collector.findings.size).to eq(3) }
71
+ end
72
+
73
+ context "ignores platform for gem compatibility if not right platform" do
74
+ Given(:script) { "gem 'rdiscount', platform: :ruby" }
75
+ When { collector.run }
76
+ Then { expect(collector.findings.size).to eq(0) }
77
+ end
78
+
79
+ context "creates a finding if platform for gem compatibility is ours" do
80
+ Given(:script) { "gem 'rdiscount', platform: :jruby" }
81
+ When { collector.run }
82
+ Then { expect(collector.findings.size).to eq(2) }
83
+ end
84
+
85
+ context "creates no finding if in wrong platform block" do
86
+ Given(:script) { "platforms :ruby { gem 'rdiscount' }" }
87
+ When { collector.run }
88
+ Then { expect(collector.findings.size).to eq(1) }
71
89
  end
72
90
 
73
91
  context "does not create a finding for a gem not mentioned in the gems info" do
74
92
  Given(:script) { "gem 'json_pure'" }
75
93
  When { collector.run }
76
- Then { collector.findings.size.should == 0 }
94
+ Then { expect(collector.findings.size).to eq(0) }
77
95
  end
78
96
 
79
97
  context "only checks calls to #gem" do
80
98
  Given(:script) { "require 'rdiscount'" }
81
99
  When { collector.run }
82
- Then { collector.findings.size.should == 0 }
100
+ Then { expect(collector.findings.size).to eq(0) }
83
101
  end
84
102
  end
85
103
 
@@ -91,8 +109,8 @@ describe JRuby::Lint::Checkers do
91
109
  "s.add_development_dependency 'ruby-debug19'\nend\n" }
92
110
 
93
111
  When { collector.run }
94
- Then { collector.findings.size.should == 2 }
95
- Then { collector.findings.detect{|f| f.message =~ /rdiscount/ }.should be_true }
112
+ Then { expect(collector.findings.size).to eq(2) }
113
+ Then { expect(collector.findings.detect{|f| f.message =~ /rdiscount/ }).to be_truthy }
96
114
  end
97
115
 
98
116
  context "Thread.critical checker" do
@@ -101,13 +119,13 @@ describe JRuby::Lint::Checkers do
101
119
  context "read" do
102
120
  Given(:script) { "begin \n Thread.critical \n end"}
103
121
  When { collector.run }
104
- Then { collector.findings.size.should == 1 }
122
+ Then { expect(collector.findings.size).to eq(1) }
105
123
  end
106
124
 
107
125
  context "assign" do
108
126
  Given(:script) { "begin \n Thread.critical = true \n ensure Thread.critical = false \n end"}
109
127
  When { collector.run }
110
- Then { collector.findings.size.should == 2 }
128
+ Then { expect(collector.findings.size).to eq(2) }
111
129
  end
112
130
  end
113
131
 
@@ -117,70 +135,53 @@ describe JRuby::Lint::Checkers do
117
135
  context "_id2ref usage" do
118
136
  Given(:script) { "ObjectSpace._id2ref(obj)"}
119
137
  When { collector.run }
120
- Then { collector.findings.size.should == 1 }
138
+ Then { expect(collector.findings.size).to eq(1) }
121
139
  end
122
140
 
123
141
  context "each_object usage" do
124
142
  Given(:script) { "ObjectSpace.each_object { }"}
125
143
  When { collector.run }
126
- Then { collector.findings.size.should == 1 }
144
+ Then { expect(collector.findings.size).to eq(1) }
127
145
  end
128
146
 
129
147
  context "each_object(Class) usage is ok" do
130
148
  Given(:script) { "ObjectSpace.each_object(Class) { }"}
131
149
  When { collector.run }
132
- Then { collector.findings.size.should == 0 }
150
+ Then { collector.findings; expect(collector.findings.size).to eq(0) }
133
151
  end
134
152
  end
135
153
 
136
- context "Timeout::timeout" do
137
- Given(:checker) { JRuby::Lint::Checkers::Timeout.new }
138
-
139
- context "::timeout usage" do
140
- Given(:script) { "Timeout::timeout(5) { sleep 10 }"}
141
- When { collector.run }
142
- Then { collector.findings.size.should == 1}
143
- end
144
-
145
- context ".timeout usage" do
146
- Given(:script) { "Timeout.timeout(5) { sleep 10 }" }
147
- When { collector.run }
148
- Then { collector.findings.size.should == 1}
149
- end
150
- end
151
-
152
-
153
154
  context "System" do
154
155
  Given(:checker) { JRuby::Lint::Checkers::System.new }
155
156
 
156
157
  context "calling ruby -v in system" do
157
158
  Given(:script) { "system('echo'); system('/usr/bin/ruby -v')"}
158
159
  When { collector.run }
159
- Then { collector.findings.size.should == 1}
160
+ Then { expect(collector.findings.size).to eq(1) }
160
161
  end
161
162
 
162
163
  context "calling ruby in the first argument to system" do
163
164
  Given(:script) { "system('/usr/bin/ruby', '-v')"}
164
165
  When { collector.run }
165
- Then { collector.findings.size.should == 1}
166
+ Then { expect(collector.findings.size).to eq(1) }
166
167
  end
167
168
 
168
169
  context "calling irb or jirb from system" do
169
170
  Given(:script) { "system('jirb'); system('irb')"}
170
171
  When { collector.run }
171
- Then { collector.findings.size.should == 2 }
172
+ Then { expect(collector.findings.size).to eq(2) }
172
173
  end
173
174
 
174
175
  context "calling a .rb file from system" do
175
176
  Given(:script) { "system('asdf.rb')" }
176
177
  When { collector.run }
177
- Then { collector.findings.size.should == 1 }
178
+ Then { expect(collector.findings.size).to eq(1) }
178
179
  end
179
180
 
180
181
  context "calling ruby -v in Kernel.system should have a finding" do
181
182
  Given(:script) { "Kernel.system('ruby -v'); Kernel.system('echo \"zomg\"')"}
182
183
  When { collector.run }
183
- Then { collector.findings.size.should == 1}
184
+ Then { expect(collector.findings.size).to eq(1) }
184
185
  end
185
186
 
186
187
  end
@@ -191,75 +192,103 @@ describe JRuby::Lint::Checkers do
191
192
  context "class variable or-assignment" do
192
193
  Given(:script) { "@@foo ||= 1" }
193
194
  When { collector.run }
194
- Then { collector.findings.size.should == 1 }
195
+ Then { expect(collector.findings.size).to eq(1) }
195
196
  end
196
197
 
197
198
  context "instance variable or-assignment" do
198
199
  Given(:script) { "@foo ||= 1" }
199
200
  When { collector.run }
200
- Then { collector.findings.size.should == 1 }
201
+ Then { expect(collector.findings.size).to eq(1) }
202
+ Then { expect(collector.findings.first.message).to be =~ /\(@foo\)/ }
201
203
  end
202
204
 
203
205
  context "attribute or-assignment" do
204
206
  Given(:script) { "foo.bar ||= 1" }
205
207
  When { collector.run }
206
- Then { collector.findings.size.should == 1 }
208
+ Then { expect(collector.findings.size).to eq(1) }
209
+ Then { expect(collector.findings.first.message).to be =~ /\(bar\)/ }
207
210
  end
208
211
 
209
212
  context "element or-assignment" do
210
213
  Given(:script) { "foo[bar] ||= 1" }
211
214
  When { collector.run }
212
- Then { collector.findings.size.should == 1 }
215
+ Then { expect(collector.findings.size).to eq(1) }
216
+ Then { expect(collector.findings.first.message).to be =~ /\(foo\[bar\]\)/ }
213
217
  end
214
218
 
215
219
  context "class variable and-assignment" do
216
220
  Given(:script) { "@@foo &&= 1" }
217
221
  When { collector.run }
218
- Then { collector.findings.size.should == 1 }
222
+ Then { expect(collector.findings.size).to eq(1) }
223
+ Then { expect(collector.findings.first.message).to be =~ /\(@@foo\)/ }
219
224
  end
220
225
 
221
226
  context "instance variable and-assignment" do
222
227
  Given(:script) { "@foo &&= 1" }
223
228
  When { collector.run }
224
- Then { collector.findings.size.should == 1 }
229
+ Then { expect(collector.findings.size).to eq(1) }
230
+ Then { expect(collector.findings.first.message).to be =~ /\(@foo\)/ }
225
231
  end
226
232
 
227
233
  context "attribute and-assignment" do
228
234
  Given(:script) { "foo.bar &&= 1" }
229
235
  When { collector.run }
230
- Then { collector.findings.size.should == 1 }
236
+ Then { expect(collector.findings.size).to eq(1) }
237
+ Then { expect(collector.findings.first.message).to be =~ /\(bar\)/ }
231
238
  end
232
239
 
233
240
  context "element and-assignment" do
234
241
  Given(:script) { "foo[bar] &&= 1" }
235
242
  When { collector.run }
236
- Then { collector.findings.size.should == 1 }
243
+ Then { expect(collector.findings.size).to eq(1) }
244
+ Then { expect(collector.findings.first.message).to be =~ /\(foo\[bar\]\)/ }
237
245
  end
238
246
 
239
- pending "needs better representation in AST" do
240
- context "class variable op-assignment" do
241
- Given(:script) { "@@foo += 1" }
242
- When { collector.run }
243
- Then { collector.findings.size.should == 1 }
244
- end
247
+ context "element and-assignment (complicated name)" do
248
+ Given(:script) { "foo[bar(2, heh)] &&= 1" }
249
+ When { collector.run }
250
+ Then { expect(collector.findings.size).to eq(1) }
251
+ Then { expect(collector.findings.first.message).to be =~ /\(foo\[bar\(2, heh\)\]\)/ }
252
+ end
253
+
254
+ context "class variable op-assignment" do
255
+ Given(:script) { "@@foo += 1" }
256
+ When { collector.run }
257
+ Then { expect(collector.findings.size).to eq(1) }
258
+ Then { expect(collector.findings.first.message).to be =~ /\(@@foo\)/ }
259
+ end
245
260
 
246
- context "instance variable op-assignment" do
247
- Given(:script) { "@foo += 1" }
248
- When { collector.run }
249
- Then { collector.findings.size.should == 1 }
250
- end
261
+ context "instance variable op-assignment" do
262
+ Given(:script) { "@foo += 1" }
263
+ When { collector.run }
264
+ Then { expect(collector.findings.size).to eq(1) }
265
+ Then { expect(collector.findings.first.message).to be =~ /\(@foo\)/ }
251
266
  end
252
267
 
253
268
  context "attribute op-assignment" do
254
269
  Given(:script) { "foo.bar += 1" }
255
270
  When { collector.run }
256
- Then { collector.findings.size.should == 1 }
271
+ Then { expect(collector.findings.size).to eq(1) }
272
+ Then { expect(collector.findings.first.message).to be =~ /\(bar\)/ }
257
273
  end
258
274
 
259
275
  context "element op-assignment" do
260
276
  Given(:script) { "foo[bar] += 1" }
261
277
  When { collector.run }
262
- Then { collector.findings.size.should == 1 }
278
+ Then { expect(collector.findings.size).to eq(1) }
279
+ Then { expect(collector.findings.first.message).to be =~ /\(foo\[bar\]\)/ }
280
+ end
281
+
282
+ context "ignores simple inst assignment" do
283
+ Given(:script) { "@foo = 1" }
284
+ When { collector.run }
285
+ Then { expect(collector.findings.size).to eq(0) }
286
+ end
287
+
288
+ context "ignores simple cvar assignment" do
289
+ Given(:script) { "@@foo = 1" }
290
+ When { collector.run }
291
+ Then { expect(collector.findings.size).to eq(0) }
263
292
  end
264
293
  end
265
294
  end