├── .amber.yml ├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── config ├── application.cr ├── database.cr ├── environments │ ├── .production.enc │ ├── development.yml │ └── test.yml ├── i18n.cr ├── initializers │ └── client_reload.cr ├── routes.cr └── webpack │ ├── common.js │ ├── development.js │ ├── entry.js │ └── production.js ├── docker-compose.yml ├── package-lock.json ├── package.json ├── public ├── crossdomain.xml ├── dist │ ├── images │ │ └── logo.svg │ ├── main.bundle.css │ └── main.bundle.js ├── favicon.ico ├── favicon.png ├── js │ └── client_reload.js └── robots.txt ├── shard.lock ├── shard.yml ├── spec └── spec_helper.cr └── src ├── assets ├── fonts │ └── .gitkeep ├── images │ ├── .gitkeep │ └── logo.svg ├── javascripts │ └── main.js └── stylesheets │ └── main.scss ├── controllers ├── application_controller.cr └── home_controller.cr ├── ruby2crystal.cr └── views ├── home └── index.slang └── layouts ├── _nav.slang └── application.slang /.amber.yml: -------------------------------------------------------------------------------- 1 | type: app 2 | database: sqlite 3 | language: slang 4 | model: granite 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /.crystal/ 4 | /.shards/ 5 | /.vscode/ 6 | /tmp/ 7 | .env 8 | .amber_secret_key 9 | production.yml 10 | .DS_Store 11 | /bin/ 12 | /node_modules/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM crystallang/crystal:0.23.1 2 | 3 | # Install Dependencies 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | RUN apt-get update -qq && apt-get install -y --no-install-recommends libpq-dev libsqlite3-dev libmysqlclient-dev libreadline-dev git curl vim netcat 6 | 7 | # Install Node 8 | RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - 9 | RUN apt-get install -y nodejs 10 | 11 | 12 | # Install Amber 13 | ENV PATH /app/bin:$PATH 14 | WORKDIR /app 15 | COPY shard.yml shard.lock /app/ 16 | RUN shards build amber 17 | 18 | # Add Project 19 | ADD . /app 20 | 21 | # Set config 22 | CMD amber watch 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Faustino Aguilar 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ruby2crystal 2 | 3 | > Please, notice this app is just using a bunch of scripts to find "keywords" in ruby code, I heavily think there are better ways to do this :P 4 | 5 | A proof of concept tool to help porting gems to shards. 6 | 7 | Highly inspired by [Crystal for Rubyist](https://github.com/crystal-lang/crystal/wiki/Crystal-for-Rubyists) wiki. 8 | 9 | Also exists [Crystal for Rubyist](http://www.crystalforrubyists.com/) book :wink: 10 | 11 | ![ruby2crystal](https://i.imgur.com/Cut4D5q.png) 12 | 13 | ## Installation 14 | 15 | ```shellsession 16 | shards build ruby2crystal 17 | ./bin/ruby2crystal 18 | ``` 19 | 20 | ## Contributing 21 | 22 | 1. Fork it ( https://github.com/faustinoaq/ruby2crystal/fork ) 23 | 2. Create your feature branch (git checkout -b my-new-feature) 24 | 3. Commit your changes (git commit -am 'Add some feature') 25 | 4. Push to the branch (git push origin my-new-feature) 26 | 5. Create a new Pull Request 27 | 28 | ## Contributors 29 | 30 | - [faustinoaq](https://github.com/faustinoaq) Faustino Aguilar - creator, maintainer 31 | -------------------------------------------------------------------------------- /config/application.cr: -------------------------------------------------------------------------------- 1 | require "./database.cr" 2 | require "./i18n.cr" 3 | require "./initializers/**" 4 | 5 | require "amber" 6 | # require "../src/models/**" 7 | 8 | require "../src/controllers/application_controller" 9 | require "../src/controllers/**" 10 | 11 | # About Application.cr File 12 | # 13 | # This is Amber application main entry point. This file is responsible for loading 14 | # initializers, classes, and all application related code in order to have 15 | # Amber::Server boot up. 16 | # 17 | # > We recommend to not modify the order of the require since the order will 18 | # affect the behavior of the application. 19 | # 20 | # With `Amber::Server.configure` block you can redefine the Server configuration 21 | # settings and use ENVIRONMENT variables and/or values evaluated at runtime. 22 | # 23 | # > Important! Yaml configurations are first class citizen and are loaded first before 24 | # this file, we recommend to use yaml configurations before changing any settings here. 25 | # Any uncommented setting here will override the YAML with the value set here. 26 | 27 | Amber::Server.configure do |settings| 28 | # Use your environment variables settings here. 29 | # 30 | # Name: A name that identifies this application. This is not internally 31 | # used by the framework. 32 | # 33 | # settings.name = "Example web application." 34 | # 35 | # 36 | # Colorize Logging: specifies whether or not to use ANSI color codes 37 | # when logging information, display the time and/or to display the severity level. 38 | # Defaults to true. 39 | # 40 | # Log Level defines the verbosity of the Amber logger. This option defaults to 41 | # debug for all environments. The available log levels are: debug, info, warn, 42 | # error, fatal, and unknown. 43 | # 44 | # settings.logging.colorize = true 45 | # settings.logging.severity = "debug" 46 | # settings.logging.filter = %w(password confirm_password) 47 | # settings.logging.skip = %w() 48 | # settings.logging.context = %w(request headers cookies session params) 49 | # 50 | # 51 | # Secret Key Base: is used for specifying a key which allows sessions 52 | # for the application to be verified against a known secure key to 53 | # prevent tampering. Applications get Amber.secret_key 54 | # initialized to a random key present in `ENV["AMBER_SECRET_KEY"]` or 55 | # `.amber_secret_key` in this order. 56 | # 57 | # settings.secret_key_base= Z0yS9n1jH8DhVXw_231pzpsZyGbAWjdndzZAd7PhlmE 58 | # 59 | # 60 | # Host: is the application server host address or ip address. Useful for when 61 | # deploying Amber to a PAAS and likely the assigned server IP is either 62 | # known or unknown. Defaults to an environment variable HOST 63 | # 64 | # settings.host = ENV["HOST"] if ENV["HOST"]? 65 | # 66 | # 67 | # Port Reuse: Amber supports clustering mode which allows to spin 68 | # multiple app instances per core. This setting allows to bind the different 69 | # instances to the same port. Default this setting to true if the number or process 70 | # is greater than 1. 71 | # 72 | # > Read more about Linux PORT REUSE https://lwn.net/Articles/542629/ 73 | # 74 | # settings.port_reuse = true 75 | # 76 | # 77 | # Process Count: This will enable Amber to be used in cluster mode, 78 | # spinning an instance for each number of process specified here. 79 | # Rule of thumb, always leave at least 1 core available for system processes/resources. 80 | # 81 | # settings.process_count = ENV["PROCESS_COUNT"].to_i if ENV["PROCESS_COUNT"]? 82 | # 83 | # 84 | # PORT: This is the port that you're application will run on. Examples would be (80, 443, 3000, 8080) 85 | # 86 | settings.port = ENV["PORT"].to_i if ENV["PORT"]? 87 | # 88 | # 89 | # Redis URL: Redis is an in memory key value storage. Amber utilizes redis as 90 | # a storing option for session information. 91 | # 92 | # settings.redis_url = ENV["REDIS_URL"] if ENV["REDIS_URL"]? 93 | # 94 | # 95 | # Database URL: This is the database connection string or data file url. 96 | # The connection string contains the information to establish a connection to the 97 | # database or the data file. Defaults to the database provider you chose at 98 | # at app generation. 99 | # 100 | # settings.database_url = ENV["DATABASE_URL"] if ENV["DATABASE_URL"]? 101 | # 102 | # 103 | # SSL Key File: The private key is a text file used initially to generate a 104 | # Certificate Signing Request (CSR), and later to secure and verify connections 105 | # using the certificate created per that request. The private key is used to create 106 | # a digital signature as you might imagine from the name, the private key should be 107 | # ``closely guarded. 108 | # 109 | # settings.ssl_key_file = ENV["SSL_KEY_FILE"] if ENV["SSL_KEY_FILE"]? 110 | # 111 | # 112 | # SSL Cert File: This represents the signed certificate file. SSL Certificates are 113 | # small data files that digitally bind a cryptographic key to an organization's 114 | # details. When installed on a web server, it activates the padlock and the https 115 | # protocol and allows secure connections from a web server to a browser. 116 | # 117 | # settings.ssl_cert_file = ENV["SSL_CERT_FILE"] if ENV["SSL_CERT_FILE"]? 118 | # 119 | # 120 | # Session: A Hash that specifies the session storage mechanism, expiration and key to be used 121 | # for the application. The `key` specifies the name of the cookie to be used defaults to 122 | # "amber.session". The store can be `encrypted_cookie`, `signed_cookie` or `redis`. Expires 123 | # when set to 0 means this is indefinitely and is expressed in seconds. 124 | # 125 | # settings.session = { "key" => "amber.session", "store" => "signed_cookie", "expires" => 0 } 126 | # 127 | # 128 | # Logger: is the logger that Amber and other capable shards in the project will use 129 | # instead of writing directly to STDOUT. Supply a custom logger to write to syslog, etc. 130 | # 131 | # settings.logger = Amber::Environment::Logger.new(File.open("example.log", "w")) 132 | # 133 | # 134 | end 135 | -------------------------------------------------------------------------------- /config/database.cr: -------------------------------------------------------------------------------- 1 | require "granite/adapter/sqlite" 2 | 3 | Granite::Adapters << Granite::Adapter::Sqlite.new({name: "sqlite", url: Amber.settings.database_url}) 4 | Granite.settings.logger = Amber.settings.logger.dup 5 | Granite.settings.logger.not_nil!.progname = "Granite" 6 | 7 | -------------------------------------------------------------------------------- /config/environments/.production.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faustinoaq/ruby2crystal/d7b910f2269ccef1418451ca3810b254e26fbb9e/config/environments/.production.enc -------------------------------------------------------------------------------- /config/environments/development.yml: -------------------------------------------------------------------------------- 1 | secret_key_base: TKHCsIAm_rXJnKUpJt6iCJeEaQDA2WA5aadYE15t_L4 2 | port: 3000 3 | name: example 4 | 5 | logging: 6 | severity: debug 7 | colorize: true 8 | filter: 9 | - password 10 | - confirm_password 11 | context: 12 | - request 13 | - session 14 | - headers 15 | - cookies 16 | - params 17 | 18 | host: 0.0.0.0 19 | port_reuse: true 20 | process_count: 1 21 | # ssl_key_file: 22 | # ssl_cert_file: 23 | redis_url: "redis://localhost:6379" 24 | database_url: sqlite3:./db/example_development.db 25 | auto_reload: true 26 | 27 | session: 28 | key: amber.session 29 | store: signed_cookie 30 | expires: 0 31 | 32 | smtp: 33 | enabled: false 34 | 35 | secrets: 36 | description: Store your development secrets credentials and settings here. 37 | -------------------------------------------------------------------------------- /config/environments/test.yml: -------------------------------------------------------------------------------- 1 | secret_key_base: GAnWH61fiYeX13d9x8ek0U9tXP5Yjmw37FZT7EzWnBQ 2 | port: 3000 3 | name: example 4 | 5 | logging: 6 | severity: debug 7 | colorize: true 8 | filter: 9 | - password 10 | - confirm_password 11 | context: 12 | - request 13 | - session 14 | - headers 15 | - cookies 16 | - params 17 | 18 | host: 0.0.0.0 19 | port_reuse: false 20 | process_count: 1 21 | # ssl_key_file: 22 | # ssl_cert_file: 23 | redis_url: "redis://localhost:6379" 24 | database_url: sqlite3:./db/example_test.db 25 | auto_reload: false 26 | 27 | session: 28 | key: amber.session 29 | store: signed_cookie 30 | expires: 0 31 | 32 | smtp: 33 | enabled: false 34 | 35 | secrets: 36 | description: Store your development secrets credentials and settings here. 37 | -------------------------------------------------------------------------------- /config/i18n.cr: -------------------------------------------------------------------------------- 1 | require "citrine-i18n" 2 | 3 | Citrine::I18n.configure do |settings| 4 | # Backend storage (as supported by i18n.cr) 5 | # settings.backend = I18n::Backend::Yaml.new 6 | 7 | # Default locale (defaults to "en" and "./src/locales/**/en.yml"). 8 | # For a new default locale to be accepted, it must be found by the 9 | # backend storage and reported in "settings.available_locales". 10 | # settings.default_locale = "en" 11 | 12 | # Separator between sublevels of data (defaults to '.') 13 | # e.g. I18n.translate("some/thing") instead of "some.thing" 14 | # settings.default_separator = '.' 15 | 16 | # Returns the current exception handler. Defaults to an instance of 17 | # I18n::ExceptionHandler. 18 | # settings.exception_handler = ExceptionHandler.new 19 | 20 | # The path from where the translations should be loaded 21 | settings.load_path += ["./src/locales"] 22 | end 23 | 24 | I18n.init 25 | -------------------------------------------------------------------------------- /config/initializers/client_reload.cr: -------------------------------------------------------------------------------- 1 | Amber::Support::ClientReload.new if Amber.settings.auto_reload? 2 | -------------------------------------------------------------------------------- /config/routes.cr: -------------------------------------------------------------------------------- 1 | Amber::Server.configure do 2 | pipeline :web do 3 | # Plug is the method to use connect a pipe (middleware) 4 | # A plug accepts an instance of HTTP::Handler 5 | if Amber.env != "production" 6 | plug Amber::Pipe::PoweredByAmber.new 7 | end 8 | # plug Amber::Pipe::ClientIp.new(["X-Forwarded-For"]) 9 | plug Citrine::I18n::Handler.new 10 | plug Amber::Pipe::Error.new 11 | plug Amber::Pipe::Logger.new 12 | plug Amber::Pipe::Session.new 13 | plug Amber::Pipe::Flash.new 14 | plug Amber::Pipe::CSRF.new 15 | end 16 | 17 | pipeline :api do 18 | plug Amber::Pipe::PoweredByAmber.new 19 | plug Amber::Pipe::Error.new 20 | plug Amber::Pipe::Logger.new 21 | plug Amber::Pipe::Session.new 22 | plug Amber::Pipe::CORS.new 23 | end 24 | 25 | # All static content will run these transformations 26 | pipeline :static do 27 | plug Amber::Pipe::PoweredByAmber.new 28 | plug Amber::Pipe::Error.new 29 | plug Amber::Pipe::Static.new("./public") 30 | end 31 | 32 | routes :web do 33 | get "/", HomeController, :index 34 | post "/", HomeController, :search 35 | end 36 | 37 | routes :api do 38 | end 39 | 40 | routes :static do 41 | # Each route is defined as follow 42 | # verb resource : String, controller : Symbol, action : Symbol 43 | get "/*", Amber::Controller::Static, :index 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /config/webpack/common.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | 5 | let config = { 6 | entry: { 7 | main: path.resolve(__dirname, 'entry.js') 8 | }, 9 | output: { 10 | filename: '[name].bundle.js', 11 | path: path.resolve(__dirname, '../../public/dist'), 12 | publicPath: '/dist' 13 | }, 14 | resolve: { 15 | alias: { 16 | amber: path.resolve(__dirname, '../../lib/amber/assets/js/amber.js') 17 | } 18 | }, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.(sass|scss|css)$/, 23 | exclude: /node_modules/, 24 | use: [ 25 | MiniCssExtractPlugin.loader, 26 | 'css-loader', 27 | 'sass-loader' 28 | ] 29 | }, 30 | { 31 | test: /\.(png|svg|jpg|gif)$/, 32 | exclude: /node_modules/, 33 | use: [ 34 | 'file-loader?name=/images/[name].[ext]' 35 | ] 36 | }, 37 | { 38 | test: /\.(woff|woff2|eot|ttf|otf)$/, 39 | exclude: /node_modules/, 40 | use: [ 41 | 'file-loader?name=/[name].[ext]' 42 | ] 43 | }, 44 | { 45 | test: /\.js$/, 46 | exclude: /node_modules/, 47 | use: { 48 | loader: 'babel-loader', 49 | options: { 50 | presets: ['@babel/preset-env'] 51 | } 52 | } 53 | } 54 | ] 55 | }, 56 | plugins: [ 57 | new MiniCssExtractPlugin({ 58 | filename: '[name].bundle.css' 59 | }) 60 | ], 61 | // For more info about webpack logs see: https://webpack.js.org/configuration/stats/ 62 | stats: 'errors-only' 63 | }; 64 | 65 | module.exports = config; 66 | -------------------------------------------------------------------------------- /config/webpack/development.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const merge = require('webpack-merge'); 3 | const common = require('./common.js'); 4 | 5 | module.exports = merge(common, { 6 | mode: 'development', 7 | devtool: 'inline-source-map' 8 | }); 9 | -------------------------------------------------------------------------------- /config/webpack/entry.js: -------------------------------------------------------------------------------- 1 | // This is the Webpack entrypoint and acts as a shim to load both the JavaScript 2 | // and CSS source files into Webpack. It is mainly here to avoid requiring 3 | // stylesheets from the javascripts asset directory and keep those concerns 4 | // separate from each other within the src directory. 5 | // 6 | // This will be removed from Webpack 5 onward. 7 | // See: https://github.com/webpack-contrib/mini-css-extract-plugin/issues/151 8 | 9 | import '../../src/assets/javascripts/main.js'; 10 | import '../../src/assets/stylesheets/main.scss'; 11 | -------------------------------------------------------------------------------- /config/webpack/production.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const merge = require('webpack-merge'); 3 | const common = require('./common.js'); 4 | 5 | module.exports = merge(common, { 6 | mode: 'production', 7 | optimization: { 8 | minimize: true 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | web: 5 | build: . 6 | image: ruby2crystal 7 | command: bash -c 'npm install && npm run watch' 8 | working_dir: /app/local 9 | volumes: 10 | - '.:/app/local' 11 | 12 | app: 13 | build: . 14 | image: ruby2crystal 15 | command: 'amber watch' 16 | working_dir: /app/local 17 | environment: 18 | DATABASE_URL: sqlite3:./db/ruby2crystal_development.db 19 | SMTP_URL: mail:1025 20 | ports: 21 | - '3000:3000' 22 | links: 23 | - db 24 | - mail 25 | volumes: 26 | - '.:/app/local' 27 | 28 | migrate: 29 | build: . 30 | image: ruby2crystal 31 | command: bash -c 'amber db migrate seed' 32 | working_dir: /app/local 33 | environment: 34 | DATABASE_URL: sqlite3:./db/ruby2crystal_development.db 35 | volumes: 36 | - '.:/app/local' 37 | links: 38 | - db 39 | 40 | mail: 41 | image: drujensen/mailcatcher:latest 42 | ports: 43 | - '1080:1080' 44 | 45 | 46 | volumes: 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruby2crystal", 3 | "version": "0.1.0", 4 | "description": "Ruby2crystal with Amber", 5 | "private": true, 6 | "author": "Amber", 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "build": "webpack --config config/webpack/development.js", 10 | "watch": "webpack -w --config config/webpack/development.js", 11 | "release": "webpack -p --config config/webpack/production.js", 12 | "test": "echo \"No test specified\" && exit 1" 13 | }, 14 | "devDependencies": { 15 | "@babel/core": "^7.2.2", 16 | "@babel/preset-env": "^7.2.3", 17 | "babel-loader": "^8.0.5", 18 | "css-loader": "^2.1.0", 19 | "file-loader": "^3.0.1", 20 | "mini-css-extract-plugin": "^0.5.0", 21 | "node-sass": "^4.9.0", 22 | "sass-loader": "^7.0.1", 23 | "webpack": "^4.28.1", 24 | "webpack-cli": "^3.2.1", 25 | "webpack-merge": "^4.1.2" 26 | }, 27 | "dependencies": { 28 | "bootstrap": "^4.2.1", 29 | "jquery": "^3.3.1", 30 | "popper.js": "^1.14.6" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /public/dist/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faustinoaq/ruby2crystal/d7b910f2269ccef1418451ca3810b254e26fbb9e/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faustinoaq/ruby2crystal/d7b910f2269ccef1418451ca3810b254e26fbb9e/public/favicon.png -------------------------------------------------------------------------------- /public/js/client_reload.js: -------------------------------------------------------------------------------- 1 | if ('WebSocket' in window) { 2 | (function () { 3 | /** 4 | * Allows to reload the browser when the server connection is lost 5 | */ 6 | function tryReload() { 7 | var request = new XMLHttpRequest(); 8 | request.open('GET', window.location.href, true); 9 | request.onreadystatechange = function () { 10 | if (request.readyState == 4) { 11 | if (request.status == 0) { 12 | setTimeout(function () { 13 | tryReload(); 14 | }, 1000) 15 | } else { 16 | window.location.reload(); 17 | } 18 | } 19 | }; 20 | request.send(); 21 | } 22 | 23 | /** 24 | * Listen server file reload 25 | */ 26 | function refreshCSS() { 27 | var sheets = [].slice.call(document.getElementsByTagName('link')); 28 | var head = document.getElementsByTagName('head')[0]; 29 | for (var i = 0; i < sheets.length; ++i) { 30 | var elem = sheets[i]; 31 | var rel = elem.rel; 32 | if (elem.href && typeof rel != 'string' || rel.length == 0 || rel.toLowerCase() == 'stylesheet') { 33 | head.removeChild(elem); 34 | var url = elem.href.replace(/(&|\\?)_cacheOverride=\\d+/, ''); 35 | elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf()); 36 | head.appendChild(elem); 37 | } 38 | } 39 | } 40 | 41 | var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://'; 42 | var address = protocol + window.location.host + '/client-reload'; 43 | var socket = new WebSocket(address); 44 | socket.onmessage = function (msg) { 45 | if (msg.data == 'reload') { 46 | tryReload(); 47 | } else if (msg.data == 'refreshcss') { 48 | refreshCSS(); 49 | } 50 | }; 51 | socket.onclose = function () { 52 | tryReload(); 53 | } 54 | })(); 55 | } 56 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /shard.lock: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | shards: 3 | amber: 4 | github: amberframework/amber 5 | version: 0.11.3 6 | 7 | amber_router: 8 | github: amberframework/amber-router 9 | version: 0.2.1 10 | 11 | callback: 12 | github: mosop/callback 13 | version: 0.6.3 14 | 15 | citrine-i18n: 16 | github: amberframework/citrine-i18n 17 | version: 0.3.2 18 | 19 | cli: 20 | github: mosop/cli 21 | version: 0.7.0 22 | 23 | compiled_license: 24 | github: elorest/compiled_license 25 | version: 0.1.3 26 | 27 | db: 28 | github: crystal-lang/crystal-db 29 | version: 0.5.1 30 | 31 | email: 32 | github: arcage/crystal-email 33 | version: 0.3.3 34 | 35 | exception_page: 36 | github: crystal-loot/exception_page 37 | version: 0.1.2 38 | 39 | garnet_spec: 40 | github: amberframework/garnet-spec 41 | version: 0.2.1 42 | 43 | granite: 44 | github: amberframework/granite 45 | version: 0.15.2 46 | 47 | i18n: 48 | github: TechMagister/i18n.cr 49 | version: 0.2.0 50 | 51 | inflector: 52 | github: phoffer/inflector.cr 53 | version: 0.1.8 54 | 55 | jasper_helpers: 56 | github: amberframework/jasper-helpers 57 | version: 0.2.4 58 | 59 | kilt: 60 | github: jeromegn/kilt 61 | version: 0.4.0 62 | 63 | liquid: 64 | github: TechMagister/liquid.cr 65 | version: 0.3.0 66 | 67 | micrate: 68 | github: amberframework/micrate 69 | version: 0.3.3 70 | 71 | mysql: 72 | github: crystal-lang/crystal-mysql 73 | version: 0.5.1 74 | 75 | optarg: 76 | github: mosop/optarg 77 | version: 0.5.8 78 | 79 | pg: 80 | github: will/crystal-pg 81 | version: 0.15.0 82 | 83 | pool: 84 | github: ysbaddaden/pool 85 | version: 0.2.3 86 | 87 | quartz_mailer: 88 | github: amberframework/quartz-mailer 89 | version: 0.5.3 90 | 91 | redis: 92 | github: stefanwille/crystal-redis 93 | version: 2.0.0 94 | 95 | selenium: 96 | github: ysbaddaden/selenium-webdriver-crystal 97 | version: 0.4.0 98 | 99 | shell-table: 100 | github: luckyframework/shell-table.cr 101 | commit: 078a04ea58ead5203bb435a3b5fff448ddabaeea 102 | 103 | slang: 104 | github: jeromegn/slang 105 | version: 1.7.1 106 | 107 | sqlite3: 108 | github: crystal-lang/crystal-sqlite3 109 | version: 0.10.0 110 | 111 | string_inflection: 112 | github: mosop/string_inflection 113 | version: 0.2.1 114 | 115 | teeplate: 116 | github: mosop/teeplate 117 | version: 0.7.0 118 | 119 | -------------------------------------------------------------------------------- /shard.yml: -------------------------------------------------------------------------------- 1 | name: ruby2crystal 2 | version: 0.1.0 3 | 4 | authors: 5 | - Amber 6 | 7 | crystal: 0.23.1 8 | 9 | license: UNLICENSED 10 | 11 | targets: 12 | ruby2crystal: 13 | main: src/ruby2crystal.cr 14 | 15 | amber: 16 | main: lib/amber/src/amber/cli.cr 17 | 18 | dependencies: 19 | amber: 20 | github: amberframework/amber 21 | version: 0.11.3 22 | #branch: master 23 | 24 | granite: 25 | github: amberframework/granite 26 | version: ~> 0.15.0 27 | 28 | quartz_mailer: 29 | github: amberframework/quartz-mailer 30 | version: ~> 0.5.1 31 | 32 | jasper_helpers: 33 | github: amberframework/jasper-helpers 34 | version: ~> 0.2.1 35 | 36 | sqlite3: 37 | github: crystal-lang/crystal-sqlite3 38 | version: ~> 0.10.0 39 | 40 | citrine-i18n: 41 | github: amberframework/citrine-i18n 42 | version: 0.3.2 43 | 44 | development_dependencies: 45 | garnet_spec: 46 | github: amberframework/garnet-spec 47 | version: ~> 0.2.1 48 | -------------------------------------------------------------------------------- /spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "garnet_spec" 3 | require "../config/*" 4 | 5 | module Spec 6 | DRIVER = :chrome 7 | PATH = "/usr/local/bin/chromedriver" 8 | 9 | # Not all server implementations will support every WebDriver feature. 10 | # Therefore, the client and server should use JSON objects with the properties 11 | # listed below when describing which features a session supports. 12 | capabilities = { 13 | browserName: "chrome", 14 | version: "", 15 | platform: "ANY", 16 | javascriptEnabled: true, 17 | takesScreenshot: true, 18 | handlesAlerts: true, 19 | databaseEnabled: true, 20 | locationContextEnabled: true, 21 | applicationCacheEnabled: true, 22 | browserConnectionEnabled: true, 23 | cssSelectorsEnabled: true, 24 | webStorageEnabled: true, 25 | rotatable: true, 26 | acceptSslCerts: true, 27 | nativeEvents: true, 28 | args: "--headless", 29 | } 30 | end 31 | -------------------------------------------------------------------------------- /src/assets/fonts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faustinoaq/ruby2crystal/d7b910f2269ccef1418451ca3810b254e26fbb9e/src/assets/fonts/.gitkeep -------------------------------------------------------------------------------- /src/assets/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faustinoaq/ruby2crystal/d7b910f2269ccef1418451ca3810b254e26fbb9e/src/assets/images/.gitkeep -------------------------------------------------------------------------------- /src/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/javascripts/main.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap'; 2 | import Amber from 'amber'; 3 | -------------------------------------------------------------------------------- /src/assets/stylesheets/main.scss: -------------------------------------------------------------------------------- 1 | $primary: #f44b4b; 2 | 3 | @import '~bootstrap/scss/bootstrap'; 4 | 5 | .main { 6 | padding-top: 20px; 7 | } 8 | 9 | .alert { 10 | margin-top: 1rem; 11 | } -------------------------------------------------------------------------------- /src/controllers/application_controller.cr: -------------------------------------------------------------------------------- 1 | require "jasper_helpers" 2 | 3 | class ApplicationController < Amber::Controller::Base 4 | include JasperHelpers 5 | LAYOUT = "application.slang" 6 | end 7 | -------------------------------------------------------------------------------- /src/controllers/home_controller.cr: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | RUBY_VERSION = "2.6.0" 3 | 4 | property found = [] of String 5 | property current_gem : String? 6 | 7 | def index 8 | render("index.slang") 9 | end 10 | 11 | def search 12 | found.clear 13 | if gem = params["gem"]? 14 | current_gem = gem 15 | msg = `gem install #{gem}` 16 | unless Dir.glob(File.expand_path("~/.gem/ruby/#{RUBY_VERSION}/gems/*")).select(&.=~ /\/#{gem}-*/).empty? 17 | found << "send found: #{`grep -rn "\.\s*send" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 18 | found << "class << found: #{`grep -rn "class <<" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 19 | # found << "$` found: #{`grep -rn "$\`" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 20 | found << "Enumerable#detect found: #{`grep -rn "\.\s*detect" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 21 | found << "Enumerable#collect found: #{`grep -rn "\.\s*collect" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 22 | found << "Enumerable#respond_to? found: #{`grep -rn "\.\s*respond_to?" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 23 | found << "length found: #{`grep -rn "\.\s*length" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 24 | found << "and found: #{`grep -rn "\s+and\s+" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 25 | found << "or found: #{`grep -rn "\s+or\s+" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 26 | # found << "posibble autosplat found: #{`grep -rn "\[\s*\[" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 27 | found << "each found (returns nil in crystal): #{`grep -rn "\.\s*each" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 28 | found << "simple quote found (use double quotes in crystal): #{`grep -rn "\'[\s\S]+\'" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 29 | found << "for loop found (use times or each in crystal): #{`grep -rn "\s*for\s+" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 30 | found << "attr_accessor found (use property keyword in crystal): #{`grep -rn "attr_accessor" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 31 | found << "attr_getter found (use getter keyword in crystal): #{`grep -rn "attr_getter" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 32 | found << "attr_setter found (use setter keyword in crystal): #{`grep -rn "attr_setter" ~/.gem/ruby/*/gems/#{gem}-*/lib`.split('\n').size - 1}\n" 33 | else 34 | flash["warning"] = "gem #{gem} not found" 35 | end 36 | found.select! do |item| 37 | !item.ends_with?(": 0\n") 38 | end 39 | render("index.slang") 40 | else 41 | raise Amber::Exceptions::RouteNotFound.new(request) 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /src/ruby2crystal.cr: -------------------------------------------------------------------------------- 1 | require "../config/*" 2 | 3 | Amber::Server.start 4 | -------------------------------------------------------------------------------- /src/views/home/index.slang: -------------------------------------------------------------------------------- 1 | div.col-sm-6 2 | h2 Welcome to Ruby2Crystal! 3 | p Try a gem name to check crystal portability score. 4 | p Inspired by 5 | a href="https://github.com/crystal-lang/crystal/wiki/Crystal-for-Rubyists" Crystal for Rubyist 6 | | wiki 7 | == form(action: "/", method: "post") do 8 | == csrf_tag 9 | div.form-group 10 | == text_field(name: "gem", value: "", placeholder: current_gem || "ruby gem name", class: "form-control") 11 | br 12 | == submit("Submit", class: "btn btn-primary btn-xs") 13 | == link_to("Reload", "/", class: "btn btn-default btn-xs") 14 | - unless found.empty? 15 | h2 Found compatibilities issues: 16 | ul 17 | - found.each do |f| 18 | li 19 | = f 20 | -------------------------------------------------------------------------------- /src/views/layouts/_nav.slang: -------------------------------------------------------------------------------- 1 | - active = context.request.path == "/" ? "active" : "" 2 | li.nav-item class=active 3 | a.nav-link href="/" Home 4 | -------------------------------------------------------------------------------- /src/views/layouts/application.slang: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title uby2crystal using Amber 5 | meta charset="utf-8" 6 | meta http-equiv="X-UA-Compatible" content="IE=edge" 7 | meta name="viewport" content="width=device-width, initial-scale=1" 8 | link rel="stylesheet" href="/dist/main.bundle.css" 9 | link rel="apple-touch-icon" href="/favicon.png" 10 | link rel="icon" href="/favicon.png" 11 | link rel="icon" type="image/x-icon" href="/favicon.ico" 12 | 13 | body 14 | nav.navbar.navbar-expand.navbar-dark.bg-primary 15 | .container 16 | a.navbar-brand href="/" 17 | img src="/dist/images/logo.svg" height="30" alt="Amber logo" 18 | ul.navbar-nav.mr-auto 19 | == render(partial: "layouts/_nav.slang") 20 | 21 | .container 22 | - flash.each do |key, value| 23 | div class="alert alert-#{key}" role="alert" 24 | = flash[key] 25 | 26 | .main== content 27 | 28 | script src="/dist/main.bundle.js" 29 | 30 | - if Amber.settings.auto_reload? 31 | script src="/js/client_reload.js" 32 | --------------------------------------------------------------------------------