ruby_crystal_codemod 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7986ec4b8202ba075699a41427f7fbcdd98b468dc08d03cdce440b9677479520
4
+ data.tar.gz: 10353a8c14d346e7dec11f6848b88ab3463f93ddb203283c245f47338676e53f
5
+ SHA512:
6
+ metadata.gz: 101ae069a8d1f6805ef80c7d5140240eb968f8e4633ef8e1ee361bf3cbb4c89c1ea695b4a3b4b524e0c579014f79747a28c86d0cc2f428bff017407e4634b504
7
+ data.tar.gz: e5578aefa628eabe37f6cf9ffc2445571bec4466031435ea97c45166cdbac3a06ae6d41651bcc459f8f5f569f28f2b9cd31a054d62c43186ff036939c8534a21
@@ -0,0 +1,103 @@
1
+ "-": &dockerbuild
2
+ steps:
3
+ - checkout
4
+
5
+ # Which version of ruby?
6
+ - run:
7
+ name: Which ruby?
8
+ command: ruby --version | tee ruby-version-for-ci.txt
9
+
10
+ # Which version of bundler?
11
+ - run:
12
+ name: Which bundler?
13
+ command: bundle -v
14
+
15
+ - run:
16
+ name: Install Crystal
17
+ command: >-
18
+ sudo apt-get update &&
19
+ sudo apt-get install apt-transport-https ca-certificates &&
20
+ curl -sSL https://dist.crystal-lang.org/apt/setup.sh | sudo bash &&
21
+ curl -sL "https://keybase.io/crystal/pgp_keys.asc" | sudo apt-key add - &&
22
+ echo "deb https://dist.crystal-lang.org/apt crystal main" | sudo tee /etc/apt/sources.list.d/crystal.list &&
23
+ sudo apt-get update &&
24
+ sudo apt-get -y install crystal &&
25
+ crystal --version
26
+
27
+ # Restore bundle cache
28
+ - restore_cache:
29
+ keys:
30
+ - bundler-packages-v2-{{ checksum "ruby-version-for-ci.txt" }}-{{ checksum "ruby_crystal_codemod.gemspec" }}
31
+
32
+ - run:
33
+ name: Bundle Install
34
+ command: bundle check || bundle install
35
+
36
+ # Restore crystal cache
37
+ - restore_cache:
38
+ keys:
39
+ - crystal-shards-{{ checksum "util/post_process_crystal/shard.lock" }}
40
+
41
+ - run:
42
+ name: Compile ./util/post_process tool
43
+ command: ./bin/compile_post_process
44
+
45
+ - run:
46
+ name: Run rspec
47
+ command: |
48
+ bundle exec rspec --profile 10 \
49
+ --format RspecJunitFormatter \
50
+ --out test_results/rspec.xml \
51
+ --format progress
52
+ - run:
53
+ name: Run RuboCop
54
+ command: |
55
+ bundle exec rake rubocop
56
+ - run:
57
+ name: Run Rufo
58
+ command: |
59
+ bundle exec rufo -c lib/ spec/lib/
60
+
61
+ # Store crystal cache
62
+ - save_cache:
63
+ key: crystal-shards-{{ checksum "util/post_process_crystal/shard.lock" }}
64
+ paths:
65
+ - util/post_process_crystal/lib/
66
+ - util/post_process_crystal/shard.lock
67
+
68
+ # Store bundle cache
69
+ - save_cache:
70
+ key: bundler-packages-v2-{{ checksum "ruby-version-for-ci.txt" }}-{{ checksum "ruby_crystal_codemod.gemspec" }}
71
+ paths:
72
+ - vendor/bundle
73
+ - Gemfile.lock
74
+
75
+ # Save test results for timing analysis
76
+ - store_test_results:
77
+ path: test_results
78
+
79
+
80
+ version: 2
81
+ jobs:
82
+ build-2-6-5:
83
+ <<: *dockerbuild
84
+ docker:
85
+ - image: circleci/ruby:2.6.5
86
+ environment:
87
+ BUNDLE_JOBS: "3"
88
+ BUNDLE_RETRY: "3"
89
+ BUNDLE_PATH: /home/circleci/project/vendor/bundle
90
+ build-2-4-5:
91
+ <<: *dockerbuild
92
+ docker:
93
+ - image: circleci/ruby:2.4.5
94
+ environment:
95
+ BUNDLE_JOBS: "3"
96
+ BUNDLE_RETRY: "3"
97
+ BUNDLE_PATH: vendor/bundle
98
+ workflows:
99
+ version: 2
100
+ test:
101
+ jobs:
102
+ - build-2-6-5
103
+ - build-2-4-5
@@ -0,0 +1,4 @@
1
+ <!--
2
+ Thank you for contributing to ruby_crystal_codemod!
3
+ Please remember to update the CHANGELOG with the contents of this PR.
4
+ -->
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /*.gem
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
14
+ sample_code
15
+
16
+ .byebug_history
17
+ # *.cr
18
+
19
+ test.rb
20
+ test.cr
21
+
22
+ util/post_process
23
+ util/post_process_crystal/lib/
24
+ *.dwarf
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,15 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "spec/**/*"
4
+ - "vendor/**/*"
5
+ TargetRubyVersion: 2.4
6
+
7
+ Layout:
8
+ Enabled: false
9
+
10
+ Metrics:
11
+ Enabled: false
12
+
13
+ Style:
14
+ Enabled: false
15
+
data/.rufo ADDED
@@ -0,0 +1,2 @@
1
+ align_case_when true
2
+ align_chained_calls true
@@ -0,0 +1,4 @@
1
+ {
2
+ "ruby.rubocop.onSave": false,
3
+ "python.linting.lintOnSave": false
4
+ }
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ruby_crystal_codemod.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard :rspec, cmd: 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Ary Borenszweig
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,141 @@
1
+ [![CircleCI](https://circleci.com/gh/DocSpring/ruby_crystal_codemod.svg?style=svg)](https://circleci.com/gh/DocSpring/ruby_crystal_codemod)
2
+
3
+ # Ruby => Crystal Codemod
4
+
5
+ This project is a fork of [Rufo](https://github.com/ruby-formatter/rufo). (Rufo and Crystal were both created by [Ary Borenszweig](https://github.com/asterite)!)
6
+
7
+ > Rufo is as an _opinionated_ ruby formatter, intended to be used via the command line as a text-editor plugin, to autoformat files on save or on demand.
8
+
9
+ The formatting rules have been modified in an attempt to produce some semi-valid Crystal code. Then you need to add some type annotations and fix any other issues manually. See the [Crystal for Rubyists](https://github.com/crystal-lang/crystal/wiki/Crystal-for-Rubyists) wiki page to learn more about the syntax differences.
10
+
11
+ > Ruby => Crystal Codemod / Rufo supports all Ruby versions >= 2.4.**5**, due to a bug in Ruby's Ripper parser.
12
+
13
+ ## Installation
14
+
15
+ Install the gem with:
16
+
17
+ ```
18
+ $ gem install ruby_crystal_codemod
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Go to the directory where you want to convert Ruby files into Crystal. Then run:
24
+
25
+ ```
26
+ ruby_crystal_codemod .
27
+ ```
28
+
29
+ This command will create new `*.cr` files and attempt to fix any simple errors. Then it will
30
+ run `crystal tool format` to format the generated code.
31
+
32
+ ## Next Steps:
33
+
34
+ * Once you've fixed all of the syntax and type errors, run `crystal tool format` to autoformat your code.
35
+ * Run [Ameba](https://github.com/crystal-ameba/ameba) for static code analysis (similar to RuboCop), and fix all of the errors.
36
+ * *(Unfortunately Ameba doesn't have a --fix option yet.)*
37
+
38
+ ## Writing Ruby / Crystal in the same file
39
+
40
+ If you want to write both Ruby and Crystal in a Ruby file, you can use some
41
+ special `#~# BEGIN <language>` and `#~# END <language>` comments.
42
+ Code between `#~# BEGIN ruby` and `#~# END ruby` should be uncommented,
43
+ and code between `#~# BEGIN crystal` and `#~# END crystal` should be commented.
44
+ When transpiling a Ruby file into Crystal, the transpiler will remove all of the Ruby lines between these comments, and it will uncomment all of the Crystal lines.
45
+
46
+ The `BEGIN` / `END` comments can start with either `#~#` or `# ~#`. (Code formatters / linters often enforce a space after the `#` character for comments.)
47
+
48
+ > This comment post-processing step is done by a Crystal program in `./util/post_process_crystal`. Run `./bin/compile_post_process` to compile the binary at `./util/post_process`.
49
+
50
+ For example, here's how you can define a class that works for both Ruby and Crystal:
51
+ (Crystal requires type annotations here.)
52
+
53
+ ```
54
+ class Foo
55
+ attr_accessor :foo
56
+
57
+ #~# BEGIN ruby
58
+ def initialize(foo)
59
+ @foo = foo
60
+ end
61
+ #~# END ruby
62
+ #~# BEGIN crystal
63
+ # @foo : Int32
64
+ # def initialize(@foo : Int32); end
65
+ #~# END crystal
66
+ end
67
+ ```
68
+
69
+ When this file is executed by Ruby, Ruby will ignore all of the commented lines. When the file is run through the Ruby => Crystal transpiler, it will be transformed into the following Crystal code:
70
+
71
+ ```
72
+ class Foo
73
+ property :foo
74
+
75
+ @foo : Int32
76
+ def initialize(@foo : Int32); end
77
+ end
78
+ ```
79
+
80
+ (The transpiler automatically renames `attr_accessor` to `property`.)
81
+
82
+ > See [`spec/fixtures/crystal_codemod_test/example.rb:87`](https://github.com/DocSpring/ruby_crystal_codemod/blob/master/spec/fixtures/crystal_codemod_test/example.rb#L87-L114) for a real-world example that is used in our acceptance specs.
83
+
84
+ ## Status
85
+
86
+ - [x] Rename all file extensions from `.rb` to `.cr`
87
+ - [x] Replace single quoted strings with double quotes
88
+ - [x] `require_relative "foo"` -> `require "./foo"`
89
+ - [x] `$:`, `LOAD_PATH` => Show error and link to docs about CRYSTAL_PATH (for compiler)
90
+ - [x] Translate methods / keywords / operators:
91
+ - [x] `include?` -> `includes?`
92
+ - [x] `key?` -> `has_key?`
93
+ - [x] `detect` -> `find`
94
+ - [x] `collect` -> `map`
95
+ - [x] `respond_to?` -> `responds_to?`
96
+ - [x] `length`, `count` -> `size`
97
+ - [x] `__dir__` -> `__DIR__`
98
+ - [x] `and` -> `&&`
99
+ - [x] `or` -> `||`
100
+ - [x] `not` -> `!`
101
+ - [x] `foo.each(&:method)` -> `foo.each(&.method)`
102
+ - [x] `foo.map &:method` -> `foo.map &.method`
103
+ - [x] `attr_accessor` => `property`
104
+ - [x] `attr_reader` => `getter`
105
+ - [x] `attr_writer` => `setter`
106
+ - [ ] `private` / `protected` methods
107
+ - [ ] `class << self` => `def self.foo` (?)
108
+ - [ ] `YAML.load_file("./foo.yml")` => `YAML.parse(File.read("./foo.yml"))`
109
+ - [ ] .each returns nil - Try to warn if it looks like the return value of `.each` is being used
110
+ - [ ] for loops - Show a warning or link to the docs
111
+ - [ ] Consistent dot notation - `File::exists?` => `File.exists?`
112
+
113
+ ## Future
114
+
115
+ * Sorbet Type Annotations -> Crystal type annotations
116
+ * Instrument a Ruby program to track of all the variable assignments at run-time. Store all of the classes that are detected in each variable (including the maximum values of integers, etc.) Convert this run-time type information into Sorbet/Crystal type annotations.
117
+
118
+ ## Testing
119
+
120
+ Run `rspec` to run all the specs and integration tests. I've kept all of the original rufo specs, because they're all really fast, it doesn't hurt to produce nicely formatted Crystal code (before the crystal format pass.)
121
+
122
+ Crystal-specific formatting specs can be found in `spec/lib/ruby_crystal_codemod/formatter_crystal_specs/*`.
123
+
124
+ There's also a Crystal acceptance spec at `spec/lib/ruby_crystal_codemod/crystal_codemod_acceptance_spec.rb`.
125
+ This transpiles the example Ruby code in `spec/fixtures/crystal_codemod_test`, and makes sure that Ruby
126
+ and Crystal produce the same output when they both run the respective code.
127
+
128
+ ## Developing
129
+
130
+ Before submitting a PR, please run:
131
+
132
+ * `bundle exec rake rubocop -a`
133
+ * `bundle exec rufo lib/ spec/lib/`
134
+
135
+ ## Contributing
136
+
137
+ Bug reports and pull requests are welcome on GitHub at https://github.com/DocSpring/ruby_crystal_codemod.
138
+
139
+ ## License
140
+
141
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rubocop/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ set -e
3
+ (cd util/post_process_crystal && shards install)
4
+ crystal build --release util/post_process_crystal/src/command.cr -o util/post_process
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ruby_crystal_codemod"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ # ruby_crystal_codemod Development
2
+
3
+ Thanks for your help!
@@ -0,0 +1,17 @@
1
+ # Releasing a gem
2
+
3
+ 1. Ensure that the tests pass and everything is working!
4
+
5
+ 2. Add missing release notes to `CHANGELOG.md`
6
+
7
+ 3. Bump version in
8
+ * `lib/ruby_crystal_codemod/version.rb`
9
+ * `CHANGELOG.md`
10
+
11
+ 4. Commit version bump via
12
+ * `git commit -v "Version X.Y.Z"`
13
+
14
+ 5. Release gem to RubyGems via
15
+ * `rake release`
16
+
17
+ 6. :tada:
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../lib/ruby_crystal_codemod"
3
+
4
+ RubyCrystalCodemod::Command.run(ARGV)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyCrystalCodemod
4
+ class Bug < StandardError; end
5
+
6
+ class SyntaxError < StandardError; end
7
+
8
+ def self.format(code, filename, dir, **options)
9
+ Formatter.format(code, filename, dir, **options)
10
+ end
11
+ end
12
+
13
+ require_relative "ruby_crystal_codemod/command"
14
+ require_relative "ruby_crystal_codemod/logger"
15
+ require_relative "ruby_crystal_codemod/dot_file"
16
+ require_relative "ruby_crystal_codemod/settings"
17
+ require_relative "ruby_crystal_codemod/formatter"
18
+ require_relative "ruby_crystal_codemod/version"
19
+ require_relative "ruby_crystal_codemod/file_finder"