rubocop-crystal 0.0.1 → 0.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da6ff9b5f99f7f17858b981c4ade0ae98dd8952b8fb2418c786f883b1e46b0fd
4
- data.tar.gz: da72279b406edb2637e76d029b8a8b8242a81baa7e47b5b6fdf2a73046b30d94
3
+ metadata.gz: 3beb9db336ee0d664fdd093775a9c14dc9512c8ec84be250ec177a6763b4924d
4
+ data.tar.gz: 015acc39018447fef5d62304bf91dddab3b66faa795149f00b3e447de6db5990
5
5
  SHA512:
6
- metadata.gz: b418ac09e30e0c12d7c3fa70968d27cdc313275eeb30a798b74320aa808cf72478a5c32c000d259938fb1b776976732c7aef88cb4ff9fd90b4c668b4fcaaad9d
7
- data.tar.gz: 8d48ac6beabda86bcc801b91eaab3479f62c9b437725349215ad50dbbee3bc013823a9bea22d8fe75a615adb63465ee20cb501cef4556c0959fc78abfd8fa9b8
6
+ metadata.gz: 2077733fe1bc6189b71854a249601f8294366a2d86cd013822bb6ec9fd1371e9229ad6622dc169426ae35c75b1f65e26f5308538a749e2b02fb7239ac99a087e
7
+ data.tar.gz: ea546caea1eeb127c946df8c97ec77ba7e5572db33c63402bba1ad4ffeeaca05d19d402d6c6a96aa37d4641f2aeda11d95a8f26a2e6b1c18a473961b8468d221
@@ -0,0 +1,26 @@
1
+ name: Test
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ runs-on: ubuntu-latest
6
+ steps:
7
+ - name: Download source
8
+ uses: actions/checkout@v4
9
+ - name: Install Crystal
10
+ uses: crystal-lang/install-crystal@v1
11
+ - name: Install Ruby
12
+ uses: ruby/setup-ruby@v1
13
+ with:
14
+ ruby-version: '3.1.2'
15
+ - name: Run tests (Ruby)
16
+ run: ruby test/string.rb
17
+ - name: Install Rubocop
18
+ run: gem install rubocop
19
+ - name: Build and install rubocop-crystal
20
+ run: |
21
+ gem build rubocop-crystal
22
+ gem install rubocop-crystal
23
+ - name: Convert test files
24
+ run: rubocop --require rubocop-crystal --fail-level fatal -A test
25
+ - name: Run tests (Crystal)
26
+ run: crystal run test/string.cr
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.0.2 (2024-08-01)
2
+
3
+ ### New features
4
+
5
+ * Enable Style/StringLiterals cop ([@zopolis4][])
6
+ * Enable Style/MethodDefParentheses cop ([@zopolis4][])
7
+ * Enable Lint/ImplicitStringConcatenation cop ([@zopolis4][])
8
+ * Add Crystal/InterpolationInSingleQuotes cop ([@zopolis4][])
9
+ * Add Crystal/RequireRelative cop ([@zopolis4][])
10
+
1
11
  ## 0.0.1 (2024-03-25)
2
12
 
3
13
  ### New features
data/README.md CHANGED
@@ -2,21 +2,32 @@
2
2
 
3
3
  The beginnings of a RuboCop extension for converting Ruby to Crystal.
4
4
 
5
- ## Testing
6
-
7
- Right now it is being tested on [basictest/test.rb](https://github.com/ruby/ruby/blob/master/basictest/test.rb) from the Ruby tree.
8
-
9
- Because that only gets to line 4, and certainly doesnt get far enough to give a pass/fail number, I am only testing it locally.
10
-
11
- Once it supports enough to run minitest, I'll convert it into a proper testing setup.
12
-
13
- ## Versioning
14
-
15
- The end goal is to be able to run everything inside `basictest`, `boostraptest`, and `test` from the Ruby tree.
16
-
17
- Minor versions are incremented when a directory now passes all tests (`basictest`, `test/json`).
18
-
19
- My sincere apologies to dedicated [0ver](https://0ver.org/) fans, but there will be a major release once all tests pass.
5
+ ## TODO
6
+
7
+ Many things. In particular, how are types going to work?
8
+
9
+ Getting static type information about Ruby files isn't the difficult part, the problem is conveying this information to the Crystal compiler while still maintaining valid syntax.
10
+
11
+ Inserting Crystal types into Ruby code is a no-go, because that causes `Lint/Syntax` errors in RuboCop.
12
+
13
+ Possible paths foward:
14
+ - Modify the parser to accept Crystal type declarations, or at least not break on them.
15
+ - Modify Crystal to accept type declarations from `.rbs` and/or `.rbi` files.
16
+ - Modify Crystal to accept type declarations from sorbet/rbs-inline/other annotations.
17
+ - Write [Ameba](https://github.com/crystal-ameba/ameba) [extension](https://crystal-ameba.github.io/2019/07/22/how-to-write-extension/) to convert the type annotations, as it works with Crystal syntax.
18
+ - Find a way to convey type information to Crystal using valid Ruby syntax.
19
+
20
+ Interesting repos:
21
+ - [rbs](https://github.com/ruby/rbs)
22
+ - [steep](https://github.com/soutaro/steep)
23
+ - [sorbet](https://github.com/sorbet/sorbet)
24
+ - [tapioca](https://github.com/Shopify/tapioca)
25
+ - [parlour](https://github.com/AaronC81/parlour)
26
+ - [gloss](https://github.com/johansenja/gloss)
27
+ - [claret](https://github.com/stevegeek/claret)
28
+ - [irbs](https://github.com/diaphragm/irbs)
29
+ - [rbs-inline](https://github.com/soutaro/rbs-inline)
30
+ - [syntax-tree-rbs](https://github.com/ruby-syntax-tree/syntax_tree-rbs)
20
31
 
21
32
  ## Installation
22
33
 
data/config/default.yml CHANGED
@@ -4,4 +4,21 @@ AllCops:
4
4
  Crystal/FileExtension:
5
5
  Description: 'This cop renames files ending in `.rb` to `.cr`.'
6
6
  Enabled: true
7
- VersionAdded: '0.0.1'
7
+
8
+ Crystal/InterpolationInSingleQuotes:
9
+ Description: "This cop uses %q in place of ' if the enclosed string would be affected by interpolation."
10
+ Enabled: true
11
+
12
+ Crystal/RequireRelative:
13
+ Description: 'This cop replaces require_relative with require while maintaining behavior.'
14
+ Enabled: true
15
+
16
+ Lint/ImplicitStringConcatenation:
17
+ Enabled: true
18
+
19
+ Style/StringLiterals:
20
+ Enabled: true
21
+ EnforcedStyle: double_quotes
22
+
23
+ Style/MethodDefParentheses:
24
+ Enabled: true
@@ -0,0 +1,35 @@
1
+ module RuboCop
2
+ module Cop
3
+ module Crystal
4
+ # In ruby, strings deliminated with single quotes do not have interpolation applied.
5
+ # Crystal does not support this, so use %q literals to replicate this functionality.
6
+ # Only do this for strings which would be affected by interpolation, and let Style/StringLiterals handle the rest.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # '#{foo}'
11
+ # 'cat #{con}'
12
+ #
13
+ # # good
14
+ # %q(#{foo})
15
+ # %q(cat #{con})
16
+ #
17
+ class InterpolationInSingleQuotes < Base
18
+ extend AutoCorrector
19
+ MSG = 'Crystal does not support the use of single-quote deliminated strings to avoid interpolation.'
20
+
21
+ def on_str(node)
22
+ # We're only interested in single-quote deliminated strings.
23
+ return unless node.source.start_with?("'")
24
+ # Replace the single quotes deliminating the string with double quotes, and check if the resulting ast is still the same.
25
+ # If it is, the string doesn't have any interpolation to avoid, and we're done here.
26
+ return if node == parse('"' + node.source[1..-2] + '"').ast
27
+
28
+ add_offense(node) do |corrector|
29
+ corrector.replace(node, '%q(' + node.source[1..-2] + ')')
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ module RuboCop
2
+ module Cop
3
+ module Crystal
4
+ # In ruby, require_relative attempts to load the library relative to the directory of the currently executing file.
5
+ # Crystal does not have require_relative, but it has the same behavior in the form of require './foo'
6
+ #
7
+ # @example
8
+ # # bad
9
+ # require_relative 'foo'
10
+ # require_relative './bar'
11
+ # require_relative '../baz'
12
+ # require_relative '/qux'
13
+ #
14
+ # # good
15
+ # require './foo'
16
+ # require './bar'
17
+ # require '../baz'
18
+ # require '/qux'
19
+ #
20
+ class RequireRelative < Base
21
+ extend AutoCorrector
22
+ MSG = 'Crystal does not support require_relative.'
23
+ RESTRICT_ON_SEND = [:require_relative]
24
+
25
+ def on_send(node)
26
+ add_offense(node) do |corrector|
27
+ if node.first_argument.value.start_with?('.', '/')
28
+ require_value = node.first_argument.value
29
+ else
30
+ require_value = "./#{node.first_argument.value}"
31
+ end
32
+ corrector.replace(node, "require '#{require_value}'")
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1 +1,3 @@
1
1
  require_relative 'crystal/file_extension'
2
+ require_relative 'crystal/interpolation_in_single_quotes'
3
+ require_relative 'crystal/require_relative'
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = 'rubocop-crystal'
3
3
  spec.summary = 'A RuboCop extension for converting Ruby to Crystal.'
4
- spec.version = '0.0.1'
4
+ spec.version = '0.0.2'
5
5
  spec.license = 'GPL-3.0-or-later'
6
6
  spec.author = 'Zopolis4'
7
7
  spec.email = 'creatorsmithmdt@gmail.com'
@@ -10,5 +10,5 @@ Gem::Specification.new do |spec|
10
10
  spec.files = `git ls-files`.split("\n")
11
11
  spec.require_paths = ['lib']
12
12
 
13
- spec.add_runtime_dependency 'rubocop'
13
+ spec.add_dependency 'rubocop', '>= 1.65.1'
14
14
  end
data/test/harness.rb ADDED
@@ -0,0 +1,41 @@
1
+ class Test
2
+ @@failed_tests = 0
3
+ @@passed_tests = 0
4
+
5
+ def self.failed_tests
6
+ @@failed_tests
7
+ end
8
+
9
+ def self.passed_tests
10
+ @@passed_tests
11
+ end
12
+
13
+ def self.assert_equal(expected, actual)
14
+ if expected == actual
15
+ @@passed_tests += 1
16
+ else
17
+ @@failed_tests += 1
18
+ puts "Assertion of equality failed:"
19
+ puts "Expected: #{expected}"
20
+ puts "Actual: #{actual}"
21
+ end
22
+ end
23
+
24
+ def self.assert_unequal(expected, actual)
25
+ if expected != actual
26
+ @@passed_tests += 1
27
+ else
28
+ @@failed_tests += 1
29
+ puts "Assertion of inequality failed:"
30
+ puts "Expected: #{expected}"
31
+ puts "Actual: #{actual}"
32
+ end
33
+ end
34
+ end
35
+
36
+ at_exit do
37
+ puts "#{Test.passed_tests} tests passed."
38
+ puts "#{Test.failed_tests} tests failed."
39
+ exit(1) if Test.failed_tests.positive?
40
+ end
41
+
data/test/string.rb ADDED
@@ -0,0 +1,20 @@
1
+ require_relative 'harness'
2
+
3
+ Test.assert_equal 'foo', "foo"
4
+ Test.assert_equal 'foo'"bar", "foobar"
5
+ Test.assert_equal "foobar", "foo" + 'bar'
6
+
7
+ foo = 'bar'
8
+ Test.assert_equal '#{foo}', '#{foo}'
9
+ Test.assert_equal 'bar', "#{foo}"
10
+
11
+ Test.assert_unequal 'bar', '#{foo}'
12
+ Test.assert_unequal "#{foo}", '#{foo}'
13
+
14
+ Test.assert_equal '#{foo}'"bar", '#{foo}bar'
15
+ Test.assert_equal "#{foo}""bar", 'bar' + "bar"
16
+
17
+
18
+ Test.assert_unequal '#{1 + 1}', '2'
19
+
20
+ Test.assert_equal '#{foo}'"bar", '#{foo}bar'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-crystal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zopolis4
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-24 00:00:00.000000000 Z
11
+ date: 2024-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -16,20 +16,21 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 1.65.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 1.65.1
27
27
  description:
28
28
  email: creatorsmithmdt@gmail.com
29
29
  executables: []
30
30
  extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
+ - ".github/workflows/test.yml"
33
34
  - ".gitignore"
34
35
  - CHANGELOG.md
35
36
  - LICENSE
@@ -37,10 +38,14 @@ files:
37
38
  - config/default.yml
38
39
  - lib/rubocop-crystal.rb
39
40
  - lib/rubocop/cop/crystal/file_extension.rb
41
+ - lib/rubocop/cop/crystal/interpolation_in_single_quotes.rb
42
+ - lib/rubocop/cop/crystal/require_relative.rb
40
43
  - lib/rubocop/cop/crystal_cops.rb
41
44
  - lib/rubocop/crystal.rb
42
45
  - lib/rubocop/crystal/inject.rb
43
46
  - rubocop-crystal.gemspec
47
+ - test/harness.rb
48
+ - test/string.rb
44
49
  homepage: https://github.com/Zopolis4/rubocop-crystal
45
50
  licenses:
46
51
  - GPL-3.0-or-later