├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── .ruby-version
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
├── assets
│ ├── config
│ │ └── manifest.js
│ ├── images
│ │ └── .keep
│ ├── javascripts
│ │ ├── application.js
│ │ ├── ast.coffee
│ │ ├── cable.js
│ │ ├── channels
│ │ │ └── .keep
│ │ ├── gist.coffee
│ │ ├── sessions.coffee
│ │ └── welcome.coffee
│ └── stylesheets
│ │ ├── application.css
│ │ ├── ast.scss
│ │ ├── gist.scss
│ │ ├── sessions.scss
│ │ ├── treeLinks.css
│ │ └── welcome.scss
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── controllers
│ ├── application_controller.rb
│ ├── ast_controller.rb
│ ├── concerns
│ │ └── .keep
│ ├── gist_controller.rb
│ ├── sessions_controller.rb
│ └── welcome_controller.rb
├── helpers
│ ├── application_helper.rb
│ ├── ast_helper.rb
│ ├── gist_helper.rb
│ ├── sessions_helper.rb
│ └── welcome_helper.rb
├── javascript
│ └── packs
│ │ ├── application.js
│ │ ├── processorList.js
│ │ ├── treeLinks.js
│ │ ├── treeitemLinks.js
│ │ └── utils.js
├── jobs
│ └── application_job.rb
├── mailers
│ └── application_mailer.rb
├── models
│ ├── application_record.rb
│ └── concerns
│ │ └── .keep
└── views
│ ├── ast
│ └── index.html.erb
│ ├── gist
│ ├── index.html.erb
│ └── show.html.erb
│ ├── layouts
│ ├── application.html.erb
│ ├── mailer.html.erb
│ └── mailer.text.erb
│ ├── shared
│ ├── _output-view.html.erb
│ ├── _source-view.html.erb
│ ├── _transform-view.html.erb
│ └── _tree-view.html.erb
│ └── welcome
│ └── index.html.erb
├── babel.config.js
├── bin
├── bundle
├── rails
├── rake
├── setup
├── update
├── webpack
├── webpack-dev-server
└── yarn
├── config.ru
├── config
├── application.rb
├── boot.rb
├── cable.yml
├── credentials.yml.enc
├── database.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── application_controller_renderer.rb
│ ├── assets.rb
│ ├── backtrace_silencers.rb
│ ├── content_security_policy.rb
│ ├── cookies_serializer.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ ├── mime_types.rb
│ ├── omniauth.rb
│ └── wrap_parameters.rb
├── locales
│ └── en.yml
├── puma.rb
├── routes.rb
├── spring.rb
├── storage.yml
├── webpack
│ ├── development.js
│ ├── environment.js
│ ├── production.js
│ └── test.js
└── webpacker.yml
├── db
└── seeds.rb
├── lib
├── assets
│ └── .keep
└── tasks
│ └── .keep
├── log
└── .keep
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── 404.html
├── 422.html
├── 500.html
├── apple-touch-icon-precomposed.png
├── apple-touch-icon.png
├── codemirror.css
├── codemirror.js
├── favicon.ico
├── images
│ ├── down-arrow-brown.png
│ └── right-arrow-brown.png
├── normalize.css
├── robots.txt
├── screenshot.png
└── solarized.css
├── storage
└── .keep
├── test
├── application_system_test_case.rb
├── controllers
│ ├── .keep
│ ├── ast_controller_test.rb
│ ├── gist_controller_test.rb
│ ├── sessions_controller_test.rb
│ └── welcome_controller_test.rb
├── fixtures
│ ├── .keep
│ └── files
│ │ └── .keep
├── helpers
│ └── .keep
├── integration
│ └── .keep
├── mailers
│ └── .keep
├── models
│ └── .keep
├── system
│ └── .keep
└── test_helper.rb
├── tmp
└── .keep
├── vendor
└── .keep
└── yarn.lock
/.browserslistrc:
--------------------------------------------------------------------------------
1 | defaults
2 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": "airbnb-base",
7 | "globals": {
8 | "Atomics": "readonly",
9 | "SharedArrayBuffer": "readonly"
10 | },
11 | "parserOptions": {
12 | "ecmaVersion": 2018,
13 | "sourceType": "module"
14 | },
15 | "rules": {
16 | 'camelcase': 0,
17 | 'no-plusplus': 0
18 | }
19 | };
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore the default SQLite database.
11 | /db/*.sqlite3
12 | /db/*.sqlite3-journal
13 |
14 | # Ignore all logfiles and tempfiles.
15 | /log/*
16 | /tmp/*
17 | !/log/.keep
18 | !/tmp/.keep
19 |
20 | # Ignore uploaded files in development
21 | /storage/*
22 | !/storage/.keep
23 |
24 | /node_modules
25 | /yarn-error.log
26 |
27 | /public/assets
28 | .byebug_history
29 |
30 | # Ignore master key for decrypting credentials and more.
31 | /config/master.key
32 |
33 | /public/packs
34 | /public/packs-test
35 | /node_modules
36 | /yarn-error.log
37 | yarn-debug.log*
38 | .yarn-integrity
39 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.5.1
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3 |
4 | ruby '2.5.5'
5 |
6 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
7 | gem 'rails', '~> 5.2.3'
8 | # Use pg as the database for Active Record
9 | gem 'pg'
10 | # Use Puma as the app server
11 | gem 'puma', '~> 4.3'
12 | # Use SCSS for stylesheets
13 | gem 'sass-rails', '~> 5.0'
14 | # Use Uglifier as compressor for JavaScript assets
15 | gem 'uglifier', '>= 1.3.0'
16 | # See https://github.com/rails/execjs#readme for more supported runtimes
17 | # gem 'mini_racer', platforms: :ruby
18 |
19 | # Use CoffeeScript for .coffee assets and views
20 | gem 'coffee-rails', '~> 4.2'
21 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
22 | gem 'turbolinks', '~> 5'
23 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
24 | gem 'jbuilder', '~> 2.5'
25 | # Use Redis adapter to run Action Cable in production
26 | # gem 'redis', '~> 4.0'
27 | # Use ActiveModel has_secure_password
28 | # gem 'bcrypt', '~> 3.1.7'
29 |
30 | # Use ActiveStorage variant
31 | # gem 'mini_magick', '~> 4.8'
32 |
33 | # Use Capistrano for deployment
34 | # gem 'capistrano-rails', group: :development
35 |
36 | # Reduces boot times through caching; required in config/boot.rb
37 | gem 'bootsnap', '>= 1.1.0', require: false
38 |
39 | group :development, :test do
40 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console
41 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
42 | end
43 |
44 | group :development do
45 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
46 | gem 'web-console', '>= 3.3.0'
47 | gem 'listen', '>= 3.0.5', '< 3.2'
48 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
49 | gem 'spring'
50 | gem 'spring-watcher-listen', '~> 2.0.0'
51 | end
52 |
53 | group :test do
54 | # Adds support for Capybara system testing and selenium driver
55 | gem 'capybara', '>= 2.15'
56 | gem 'selenium-webdriver'
57 | # Easy installation and use of chromedriver to run system tests with Chrome
58 | gem 'chromedriver-helper'
59 | end
60 |
61 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
62 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
63 |
64 | gem 'parser'
65 | gem 'jquery-rails'
66 | gem 'gist', git: 'https://github.com/rajasegar/gist.git', ref: '55c2247'
67 | gem 'omniauth-github'
68 | gem 'octokit'
69 |
70 | gem 'webpacker', '~> 4.x'
71 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GIT
2 | remote: https://github.com/rajasegar/gist.git
3 | revision: 55c2247bfc59c29e5a6ba2f25f704b8fc86cc1de
4 | ref: 55c2247
5 | specs:
6 | gist (5.0.0)
7 |
8 | GEM
9 | remote: https://rubygems.org/
10 | specs:
11 | actioncable (5.2.3)
12 | actionpack (= 5.2.3)
13 | nio4r (~> 2.0)
14 | websocket-driver (>= 0.6.1)
15 | actionmailer (5.2.3)
16 | actionpack (= 5.2.3)
17 | actionview (= 5.2.3)
18 | activejob (= 5.2.3)
19 | mail (~> 2.5, >= 2.5.4)
20 | rails-dom-testing (~> 2.0)
21 | actionpack (5.2.3)
22 | actionview (= 5.2.3)
23 | activesupport (= 5.2.3)
24 | rack (~> 2.0)
25 | rack-test (>= 0.6.3)
26 | rails-dom-testing (~> 2.0)
27 | rails-html-sanitizer (~> 1.0, >= 1.0.2)
28 | actionview (5.2.3)
29 | activesupport (= 5.2.3)
30 | builder (~> 3.1)
31 | erubi (~> 1.4)
32 | rails-dom-testing (~> 2.0)
33 | rails-html-sanitizer (~> 1.0, >= 1.0.3)
34 | activejob (5.2.3)
35 | activesupport (= 5.2.3)
36 | globalid (>= 0.3.6)
37 | activemodel (5.2.3)
38 | activesupport (= 5.2.3)
39 | activerecord (5.2.3)
40 | activemodel (= 5.2.3)
41 | activesupport (= 5.2.3)
42 | arel (>= 9.0)
43 | activestorage (5.2.3)
44 | actionpack (= 5.2.3)
45 | activerecord (= 5.2.3)
46 | marcel (~> 0.3.1)
47 | activesupport (5.2.3)
48 | concurrent-ruby (~> 1.0, >= 1.0.2)
49 | i18n (>= 0.7, < 2)
50 | minitest (~> 5.1)
51 | tzinfo (~> 1.1)
52 | addressable (2.8.0)
53 | public_suffix (>= 2.0.2, < 5.0)
54 | archive-zip (0.12.0)
55 | io-like (~> 0.3.0)
56 | arel (9.0.0)
57 | ast (2.4.0)
58 | bindex (0.8.1)
59 | bootsnap (1.4.5)
60 | msgpack (~> 1.0)
61 | builder (3.2.3)
62 | byebug (11.0.1)
63 | capybara (3.29.0)
64 | addressable
65 | mini_mime (>= 0.1.3)
66 | nokogiri (~> 1.8)
67 | rack (>= 1.6.0)
68 | rack-test (>= 0.6.3)
69 | regexp_parser (~> 1.5)
70 | xpath (~> 3.2)
71 | childprocess (2.0.0)
72 | rake (< 13.0)
73 | chromedriver-helper (2.1.1)
74 | archive-zip (~> 0.10)
75 | nokogiri (~> 1.8)
76 | coffee-rails (4.2.2)
77 | coffee-script (>= 2.2.0)
78 | railties (>= 4.0.0)
79 | coffee-script (2.4.1)
80 | coffee-script-source
81 | execjs
82 | coffee-script-source (1.12.2)
83 | concurrent-ruby (1.1.5)
84 | crass (1.0.5)
85 | erubi (1.8.0)
86 | execjs (2.7.0)
87 | faraday (0.15.4)
88 | multipart-post (>= 1.2, < 3)
89 | ffi (1.11.1)
90 | globalid (0.4.2)
91 | activesupport (>= 4.2.0)
92 | hashie (3.6.0)
93 | i18n (1.6.0)
94 | concurrent-ruby (~> 1.0)
95 | io-like (0.3.0)
96 | jbuilder (2.9.1)
97 | activesupport (>= 4.2.0)
98 | jquery-rails (4.3.5)
99 | rails-dom-testing (>= 1, < 3)
100 | railties (>= 4.2.0)
101 | thor (>= 0.14, < 2.0)
102 | jwt (2.2.1)
103 | listen (3.1.5)
104 | rb-fsevent (~> 0.9, >= 0.9.4)
105 | rb-inotify (~> 0.9, >= 0.9.7)
106 | ruby_dep (~> 1.2)
107 | loofah (2.3.1)
108 | crass (~> 1.0.2)
109 | nokogiri (>= 1.5.9)
110 | mail (2.7.1)
111 | mini_mime (>= 0.1.1)
112 | marcel (0.3.3)
113 | mimemagic (~> 0.3.2)
114 | method_source (0.9.2)
115 | mimemagic (0.3.10)
116 | nokogiri (~> 1)
117 | rake
118 | mini_mime (1.0.2)
119 | mini_portile2 (2.6.1)
120 | minitest (5.11.3)
121 | msgpack (1.3.1)
122 | multi_json (1.13.1)
123 | multi_xml (0.6.0)
124 | multipart-post (2.1.1)
125 | nio4r (2.5.8)
126 | nokogiri (1.12.5)
127 | mini_portile2 (~> 2.6.1)
128 | racc (~> 1.4)
129 | oauth2 (1.4.1)
130 | faraday (>= 0.8, < 0.16.0)
131 | jwt (>= 1.0, < 3.0)
132 | multi_json (~> 1.3)
133 | multi_xml (~> 0.5)
134 | rack (>= 1.2, < 3)
135 | octokit (4.14.0)
136 | sawyer (~> 0.8.0, >= 0.5.3)
137 | omniauth (1.9.0)
138 | hashie (>= 3.4.6, < 3.7.0)
139 | rack (>= 1.6.2, < 3)
140 | omniauth-github (1.3.0)
141 | omniauth (~> 1.5)
142 | omniauth-oauth2 (>= 1.4.0, < 2.0)
143 | omniauth-oauth2 (1.6.0)
144 | oauth2 (~> 1.1)
145 | omniauth (~> 1.9)
146 | parser (2.6.4.0)
147 | ast (~> 2.4.0)
148 | pg (1.1.4)
149 | public_suffix (4.0.6)
150 | puma (4.3.9)
151 | nio4r (~> 2.0)
152 | racc (1.5.2)
153 | rack (2.2.3)
154 | rack-proxy (0.6.5)
155 | rack
156 | rack-test (1.1.0)
157 | rack (>= 1.0, < 3)
158 | rails (5.2.3)
159 | actioncable (= 5.2.3)
160 | actionmailer (= 5.2.3)
161 | actionpack (= 5.2.3)
162 | actionview (= 5.2.3)
163 | activejob (= 5.2.3)
164 | activemodel (= 5.2.3)
165 | activerecord (= 5.2.3)
166 | activestorage (= 5.2.3)
167 | activesupport (= 5.2.3)
168 | bundler (>= 1.3.0)
169 | railties (= 5.2.3)
170 | sprockets-rails (>= 2.0.0)
171 | rails-dom-testing (2.0.3)
172 | activesupport (>= 4.2.0)
173 | nokogiri (>= 1.6)
174 | rails-html-sanitizer (1.2.0)
175 | loofah (~> 2.2, >= 2.2.2)
176 | railties (5.2.3)
177 | actionpack (= 5.2.3)
178 | activesupport (= 5.2.3)
179 | method_source
180 | rake (>= 0.8.7)
181 | thor (>= 0.19.0, < 2.0)
182 | rake (12.3.3)
183 | rb-fsevent (0.10.3)
184 | rb-inotify (0.10.0)
185 | ffi (~> 1.0)
186 | regexp_parser (1.6.0)
187 | ruby_dep (1.5.0)
188 | rubyzip (1.3.0)
189 | sass (3.7.4)
190 | sass-listen (~> 4.0.0)
191 | sass-listen (4.0.0)
192 | rb-fsevent (~> 0.9, >= 0.9.4)
193 | rb-inotify (~> 0.9, >= 0.9.7)
194 | sass-rails (5.1.0)
195 | railties (>= 5.2.0)
196 | sass (~> 3.1)
197 | sprockets (>= 2.8, < 4.0)
198 | sprockets-rails (>= 2.0, < 4.0)
199 | tilt (>= 1.1, < 3)
200 | sawyer (0.8.2)
201 | addressable (>= 2.3.5)
202 | faraday (> 0.8, < 2.0)
203 | selenium-webdriver (3.142.4)
204 | childprocess (>= 0.5, < 3.0)
205 | rubyzip (~> 1.2, >= 1.2.2)
206 | spring (2.1.0)
207 | spring-watcher-listen (2.0.1)
208 | listen (>= 2.7, < 4.0)
209 | spring (>= 1.2, < 3.0)
210 | sprockets (3.7.2)
211 | concurrent-ruby (~> 1.0)
212 | rack (> 1, < 3)
213 | sprockets-rails (3.2.1)
214 | actionpack (>= 4.0)
215 | activesupport (>= 4.0)
216 | sprockets (>= 3.0.0)
217 | thor (0.20.3)
218 | thread_safe (0.3.6)
219 | tilt (2.0.9)
220 | turbolinks (5.2.0)
221 | turbolinks-source (~> 5.2)
222 | turbolinks-source (5.2.0)
223 | tzinfo (1.2.5)
224 | thread_safe (~> 0.1)
225 | uglifier (4.1.20)
226 | execjs (>= 0.3.0, < 3)
227 | web-console (3.7.0)
228 | actionview (>= 5.0)
229 | activemodel (>= 5.0)
230 | bindex (>= 0.4.0)
231 | railties (>= 5.0)
232 | webpacker (4.0.7)
233 | activesupport (>= 4.2)
234 | rack-proxy (>= 0.6.1)
235 | railties (>= 4.2)
236 | websocket-driver (0.7.1)
237 | websocket-extensions (>= 0.1.0)
238 | websocket-extensions (0.1.5)
239 | xpath (3.2.0)
240 | nokogiri (~> 1.8)
241 |
242 | PLATFORMS
243 | ruby
244 |
245 | DEPENDENCIES
246 | bootsnap (>= 1.1.0)
247 | byebug
248 | capybara (>= 2.15)
249 | chromedriver-helper
250 | coffee-rails (~> 4.2)
251 | gist!
252 | jbuilder (~> 2.5)
253 | jquery-rails
254 | listen (>= 3.0.5, < 3.2)
255 | octokit
256 | omniauth-github
257 | parser
258 | pg
259 | puma (~> 4.3)
260 | rails (~> 5.2.3)
261 | sass-rails (~> 5.0)
262 | selenium-webdriver
263 | spring
264 | spring-watcher-listen (~> 2.0.0)
265 | turbolinks (~> 5)
266 | tzinfo-data
267 | uglifier (>= 1.3.0)
268 | web-console (>= 3.3.0)
269 | webpacker (~> 4.x)
270 |
271 | RUBY VERSION
272 | ruby 2.5.5p157
273 |
274 | BUNDLED WITH
275 | 2.0.2
276 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ruby-ast-explorer
2 |
3 | AST Explorer lets you to visualize your ruby code as AST(Abstract Syntax Trees).
4 |
5 | This uses the [parser](https://github.com/whitequark/parser) gem to convert the source code into ASTs
6 | and the [TreeWriter](https://www.rubydoc.info/github/whitequark/parser/Parser/TreeRewriter) class
7 | of the gem to apply transformations on the AST nodes and convert them back to source code.
8 |
9 | We can take the transformation logic and put into a ruby file like `transform.rb` and use
10 | the same to do large scale refactorings with your ruby code base using tools like [codeshift](https://github.com/rajasegar/codeshift) and [cybertron](https://github.com/rajasegar/cybertron).
11 |
12 | ```sh
13 | $ codeshift -t transform.rb app/models/**/*.rb
14 | ```
15 |
16 | ## Export as gist
17 | You can also export the source and transform code as gist to your Github account by clicking
18 | the `Export as gist` button. But before that you need to sign in with Github and give permission to create gists for this app named ruby-ast-explorer.
19 |
20 |
21 | And with that you can directly use the transform from your gist.
22 | ```sh
23 | $ codeshift -t https://gist.githubusercontent.com/[user]/.../transform.rb app/models/**/*.rb
24 | ```
25 |
26 | It has got four panes with the following content:
27 |
28 | * Top-Left => Original Source Code
29 | * Top-Right => AST in Tree and S-expressions formats
30 | * Bottom-Left => Transform Class
31 | * Bottom-Right => Output
32 |
33 | 
34 |
35 |
36 | ## Reference:
37 | * https://whitequark.org/blog/2013/04/26/lets-play-with-ruby-code/
38 | * https://blog.arkency.com/using-ruby-parser-and-ast-tree-to-find-deprecated-syntax/
39 | * https://blog.arkency.com/rewriting-deprecated-apis-with-parser-gem/
40 | * https://gist.github.com/jonatas/e70c874cbbd0cac5a9abd9f4a78fa816
41 | * https://github.com/jonatas/fast
42 | * http://www.zenspider.com/projects/ruby2ruby.html
43 | * [Parsing Ruby](https://whitequark.org/blog/2012/10/02/parsing-ruby/)
44 | * [awesome-ruby-ast](https://github.com/rajasegar/awesome-ruby-ast)
45 |
46 | Inspired by [AST Explorer](https://astexplorer.net) by [Felix Kling](https://github.com/fkling)
47 |
48 | ## Tools
49 | * [parser gem](https://github.com/whitequark/parser)
50 | * [CodeMirror](https://codemirror.net/)
51 |
52 | ## Other related tools
53 | * [Astrolabe](https://github.com/yujinakayama/astrolabe)
54 | * [codeshift](https://github.com/rajasegar/codeshift)
55 | * [cybertron](https://github.com/rajasegar/cybertron)
56 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require_relative 'config/application'
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../javascripts .js
3 | //= link_directory ../stylesheets .css
4 |
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/app/assets/images/.keep
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
5 | // vendor/assets/javascripts directory can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file. JavaScript code in this file should be added after the last require_* statement.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require rails-ujs
14 | //= require activestorage
15 | //= require turbolinks
16 | //= require_tree .
17 | //= require jquery
18 | //= require jquery_ujs
19 |
--------------------------------------------------------------------------------
/app/assets/javascripts/ast.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/cable.js:
--------------------------------------------------------------------------------
1 | // Action Cable provides the framework to deal with WebSockets in Rails.
2 | // You can generate new channels where WebSocket features live using the `rails generate channel` command.
3 | //
4 | //= require action_cable
5 | //= require_self
6 | //= require_tree ./channels
7 |
8 | (function() {
9 | this.App || (this.App = {});
10 |
11 | App.cable = ActionCable.createConsumer();
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/app/assets/javascripts/channels/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/app/assets/javascripts/channels/.keep
--------------------------------------------------------------------------------
/app/assets/javascripts/gist.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/sessions.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/welcome.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
6 | * vendor/assets/stylesheets directory can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10 | * files in this directory. Styles in this file should be added after the last require_* statement.
11 | * It is generally better to create a new file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 | body {
17 | font-family: Helvetica, sans-serif;
18 | font-size: 13px;
19 | padding-top: 2.5rem;
20 | padding-bottom: 2.5rem;
21 | overflow: hidden;
22 | }
23 |
24 |
25 | .dark-theme footer {
26 | background: #343a40;
27 | color: #fff;
28 | }
29 |
30 | .dark-theme .custom-control-label {
31 | color: #fff;
32 | }
33 |
34 | h1 {
35 | font-size: larger;
36 | }
37 |
38 | header {
39 | display: grid;
40 | grid-template-columns: auto 200px;
41 | }
42 |
43 | footer {
44 | text-align: center;
45 | position:fixed;
46 | bottom: 0;
47 | background: #f8f9fa;
48 | width: 100%;
49 | z-index: 9999;
50 | height: 30px;
51 | line-height: 30px;
52 | }
53 |
54 | footer p {
55 | margin-bottom: 0;
56 | }
57 |
58 | .navbar {
59 | padding: 0 1rem;
60 | }
61 |
62 |
63 |
64 | #tab-wrapper {
65 | border: 1px solid #dee2e6;
66 | background: #eee;
67 | }
68 |
69 | .tab-content {
70 | max-height: 40vh;
71 | overflow: auto;
72 | }
73 |
74 | .styled-background {
75 | background-color: #ff7;
76 | }
77 |
78 |
79 | .container-fluid {
80 | padding-left: 1em;
81 | padding-right: 0;
82 | }
83 |
84 | .CodeMirror {
85 | height: calc((100vh - 70px)/2);
86 | max-height: calc((100vh - 70px)/2);
87 | }
88 |
89 |
90 | .col-6 {
91 | border-bottom: 2px solid #ddd;
92 | padding: 0;
93 | }
94 |
95 | .col-6:nth-child(odd) {
96 | border-right: 2px solid #ddd;
97 | }
98 |
99 | .cm-s-solarized.CodeMirror {
100 | box-shadow: none;
101 | }
102 |
103 | .custom-control-label {
104 | color: white;
105 | }
106 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/ast.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the ast controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/gist.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the gist controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/sessions.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the sessions controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/treeLinks.css:
--------------------------------------------------------------------------------
1 | ul[role="tree"] {
2 | margin: 0 0 0 1em;
3 | padding: 0;
4 | list-style: none;
5 | font-family: monospace, serif;
6 | }
7 |
8 | ul[role="tree"] li {
9 | margin: 0;
10 | padding: 0;
11 | list-style: none;
12 | cursor: pointer;
13 | }
14 |
15 | ul[role="tree"] a {
16 | text-decoration: underline;
17 | border-color: transparent;
18 | }
19 |
20 | [role="treeitem"] ul {
21 | margin: 0;
22 | padding: 0;
23 | margin-left: 0.9em;
24 | }
25 |
26 | [role="treeitem"][aria-expanded="false"] > ul {
27 | display: none;
28 | }
29 |
30 | [role="treeitem"][aria-expanded="true"] > ul {
31 | display: block;
32 | }
33 |
34 | [role="treeitem"][aria-expanded="false"] > span::before {
35 | content: "+";
36 | position: relative;
37 | right: 0.5em;
38 | color: green;
39 | }
40 |
41 | [role="treeitem"][aria-expanded="true"] > span::before {
42 | content: "-";
43 | position: relative;
44 | right: 0.5em;
45 | color: red;
46 | }
47 |
48 | [role="treeitem"],
49 | [role="treeitem"] span {
50 | width: 16em;
51 | margin: 0;
52 | padding: 0.125em;
53 | display: block;
54 | color: #B58900;
55 | }
56 |
57 | /* disable default keyboard focus styling for treeitems
58 | Keyboard focus is styled with the following CSS */
59 | [role="treeitem"]:focus {
60 | outline: 0;
61 | }
62 |
63 | [role="treeitem"].focus,
64 | [role="treeitem"] span.focus {
65 | border-color: black;
66 | background-color: #eee;
67 | }
68 |
69 | [role="treeitem"].hover,
70 | [role="treeitem"] span.hover {
71 | background-color: #ddd;
72 | }
73 |
74 | [role="treeitem"] span:hover {
75 | background-color: #ddd;
76 | }
77 |
78 | span.blue {
79 | color: blue;
80 | display: inline;
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/welcome.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the welcome controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/controllers/ast_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'parser/current'
4 | require 'json'
5 |
6 | # AST Controller
7 | class AstController < ApplicationController
8 | def index
9 | @ast = Parser::CurrentRuby.parse('2 + 2')
10 | p @ast
11 | respond_to do |format|
12 | format.json { render json: { ast: @ast } }
13 | end
14 | end
15 |
16 | def create
17 | @source_code = params[:code]
18 | @transform = params[:transform]
19 |
20 | ast = Parser::CurrentRuby.parse(params[:code])
21 |
22 | # Doing eval is not that safe, need to sanitize
23 | eval(params[:transform])
24 |
25 | buffer = Parser::Source::Buffer.new('(example)')
26 | buffer.source = params[:code]
27 | # begin
28 | temp = Parser::CurrentRuby.parse(params[:code])
29 | rewriter = Transform.new
30 |
31 | # Rewrite the AST, returns a String with the new form.
32 | output = rewriter.rewrite(buffer, temp)
33 | # rescue StandardError
34 | # output = params[:code]
35 | # end
36 |
37 | respond_to do |format|
38 | format.json { render json: { ast: ast.to_s, output: output.to_s, treeData: ast.to_json } }
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/controllers/gist_controller.rb:
--------------------------------------------------------------------------------
1 | class GistController < ApplicationController
2 |
3 | def ast_explorer_gist?(files)
4 | if files
5 | files.has_key?("transform.rb") and files.has_key?("source.rb")
6 | else
7 | false
8 | end
9 | end
10 |
11 | def index
12 | response = Gist.list_all_gists("",{ :access_token => session[:github_token]})
13 | @gists = JSON.parse(response.body).select { |gist| ast_explorer_gist?(gist['files']) }
14 | end
15 |
16 | def show
17 | gist_id = params[:id]
18 |
19 | # Also need to check if he is the owner of the gist
20 | if session[:user_id]
21 | session[:gist_id] = gist_id
22 | end
23 | @transform = Gist.read_gist( gist_id, 'transform.rb', { :access_token => session[:github_token]})
24 | @source_code = Gist.read_gist( gist_id, 'source.rb', { :access_token => session[:github_token]})
25 | end
26 |
27 |
28 | def create
29 | source = params[:code]
30 | transform = params[:transform]
31 | yml = "v:1\nparser:2.6.3.0\nrails:5.2.3\nruby:2.5.5p157"
32 | response = Gist.multi_gist({"source.rb" => source, "transform.rb" => transform, "ruby-ast-explorer.yml" => yml},
33 | :public => true,
34 | :description => "A Gist generated by ruby-ast-explorer",
35 | :access_token => session[:github_token])
36 | session[:gist_id] = response['id']
37 | respond_to do |format|
38 | format.json { render :json => { message: "Exported to gist with name = ruby-ast-explorer.yml successfully.", gist: response['id'] } }
39 | end
40 | end
41 |
42 | def update
43 | source = params[:code]
44 | transform = params[:transform]
45 | response = Gist.multi_gist({"source.rb" => source, "transform.rb" => transform },
46 | :access_token => session[:github_token],
47 | :update => params[:id])
48 | respond_to do |format|
49 | format.json { render :json => { message: "Updated gist with name = ruby-ast-explorer.yml successfully.", gist: response['id'] } }
50 | end
51 | end
52 |
53 | end
54 |
--------------------------------------------------------------------------------
/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class SessionsController < ApplicationController
2 | def create
3 | auth = request.env["omniauth.auth"]
4 | #pp auth
5 | session[:user_id] = auth["uid"]
6 | session[:github_token] = auth.credentials.token
7 | redirect_to root_url, :notice => "Signed in!"
8 | end
9 |
10 | def destroy
11 | session[:user_id] = nil
12 | redirect_to root_url, :notice => "Signed out!"
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/app/controllers/welcome_controller.rb:
--------------------------------------------------------------------------------
1 | class WelcomeController < ApplicationController
2 | def index
3 | if session[:user_id] == nil
4 | redirect_to '/auth/github'
5 | end
6 | session[:gist_id] = nil
7 | @transform = %{# Your Transform Class should always extend from
8 | # Parser:: TreeRewriter
9 | class Transform < Parser::TreeRewriter
10 | def on_lvasgn(node)
11 | # Reverse the variable names
12 | replace(node.loc.name, node.children[0].to_s.reverse)
13 | end
14 |
15 | def on_def(node)
16 | replace(node.loc.name, node.children[0].to_s.reverse)
17 | end
18 | end}
19 |
20 | @source_code = %q(# Paste some ruby code here and
21 | # check the generated AST on the right
22 | tips = [
23 | "Click on any AST node with a '+' to expand it",
24 |
25 | "Hovering over a node highlights the \
26 | corresponding part in the source code",
27 | ]
28 | def print_tips
29 | tips.each { |key, value| print "Tip #{key}: #{value}" }
30 | end)
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | def flash_class(level)
3 | case level
4 | when :notice then "alert alert-info"
5 | when :success then "alert alert-success"
6 | when :error then "alert alert-error"
7 | when :alert then "alert alert-error"
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/app/helpers/ast_helper.rb:
--------------------------------------------------------------------------------
1 | module AstHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/gist_helper.rb:
--------------------------------------------------------------------------------
1 | module GistHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/sessions_helper.rb:
--------------------------------------------------------------------------------
1 | module SessionsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/welcome_helper.rb:
--------------------------------------------------------------------------------
1 | module WelcomeHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/javascript/packs/application.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | /* globals CodeMirror $ */
3 |
4 | import {
5 | debounce,
6 | buildTreeView,
7 | indentCode,
8 | } from './utils';
9 |
10 | document.addEventListener('turbolinks:load', () => {
11 | const markers = [];
12 |
13 | const editorOptions = {
14 | mode: 'text/x-ruby',
15 | matchBrackets: true,
16 | indentUnit: 2,
17 | lineNumbers: true,
18 | theme: 'solarized',
19 | styleSelectedText: true,
20 | };
21 |
22 | const astEditorOptions = {
23 | mode: 'text/x-ruby',
24 | matchBrackets: true,
25 | indentUnit: 2,
26 | theme: 'solarized',
27 | readOnly: true,
28 | };
29 |
30 |
31 | const editor = CodeMirror.fromTextArea(document.getElementById('editor'), editorOptions);
32 | const transformEditor = CodeMirror.fromTextArea(document.getElementById('transform-editor'), editorOptions);
33 | const outputEditor = CodeMirror.fromTextArea(document.getElementById('output-editor'), editorOptions);
34 | const astEditor = CodeMirror.fromTextArea(document.getElementById('ast-editor'), astEditorOptions);
35 |
36 |
37 | function indentAll() {
38 | indentCode(editor);
39 | indentCode(transformEditor);
40 | indentCode(outputEditor);
41 | }
42 |
43 |
44 | function updateAst(code, transform) {
45 | $.ajax({
46 | url: '/ast',
47 | type: 'post',
48 | data: { code, transform },
49 | success(data) {
50 | astEditor.setValue(data.ast);
51 | buildTreeView(data.treeData);
52 | outputEditor.setValue(data.output);
53 | },
54 | error() {},
55 | });
56 | }
57 |
58 | function updateOutput(code, transform) {
59 | $.ajax({
60 | url: '/ast',
61 | type: 'post',
62 | data: { code, transform },
63 | success(data) {
64 | outputEditor.setValue(data.output);
65 | },
66 | error() {},
67 | });
68 | }
69 |
70 |
71 | updateAst(editor.getValue(), transformEditor.getValue());
72 |
73 | indentAll();
74 |
75 |
76 | editor.on('change', debounce((cm) => {
77 | const code = cm.getValue();
78 | const transform = transformEditor.getValue();
79 | updateAst(code, transform);
80 | }, 250));
81 |
82 | editor.on('cursorActivity', (e) => {
83 | // Collapse all items first
84 | const trees = document.querySelectorAll('[role="tree"]');
85 | for (let i = 0; i < trees.length; i++) {
86 | trees[i].attributes['aria-expanded'] = 'false';
87 | }
88 |
89 |
90 | const { line } = e.doc.getCursor(); // Cursor line
91 | const { ch } = e.doc.getCursor(); // Cursor character
92 |
93 | console.log({ line, ch });
94 |
95 | const doc = editor.getDoc();
96 |
97 | let pos = 0;
98 | for (let index = 0; index <= line; index++) {
99 | const lineLength = doc.getLine(index).length; // Adding 1 for new line
100 |
101 | pos += lineLength;
102 | }
103 |
104 | pos += ch;
105 |
106 |
107 | const nodes = Array.from(document.querySelectorAll('li')).filter((el) => {
108 | const { beginPos, endPos } = el.dataset;
109 | return pos > beginPos && pos < endPos;
110 | });
111 |
112 | nodes.forEach((node) => {
113 | // HACK: to open full tree branch
114 | if (node.parentElement && node.parentElement.parentElement) {
115 | // node.parentElement.parentElement.click();
116 | node.parentElement.parentElement.attributes['aria-expanded'] = 'true';
117 | }
118 | // node.click();
119 | // node.style.backgroundColor = 'yellow';
120 | node.attributes['aria-expanded'] = 'true';
121 | });
122 | });
123 |
124 |
125 | transformEditor.on('change', debounce((cm) => {
126 | const transform = cm.getValue();
127 | const code = editor.getValue();
128 | updateOutput(code, transform);
129 | }, 250));
130 |
131 | $('#create-gist').click(function () {
132 | const _self = this;
133 | _self.disabled = true;
134 | $.ajax({
135 | url: '/gist',
136 | type: 'post',
137 | data: { code: editor.getValue(), transform: transformEditor.getValue() },
138 | success(data) {
139 | // window.alert(data.message);
140 | // _self.disabled = false;
141 | window.location = `/gist/${data.gist}`;
142 | },
143 | error(data) {
144 | window.alert('Gist creation failed');
145 | _self.disabled = false;
146 | },
147 | });
148 | });
149 |
150 | $('#update-gist').click(function () {
151 | const _self = this;
152 | _self.disabled = true;
153 | const gistId = window.location.pathname.replace('/gist/', '');
154 | $.ajax({
155 | url: `/gist/${gistId}`,
156 | type: 'put',
157 | data: { code: editor.getValue(), transform: transformEditor.getValue() },
158 | success(data) {
159 | window.alert(data.message);
160 | _self.disabled = false;
161 | },
162 | error(data) {
163 | window.alert('Gist update failed');
164 | _self.disabled = false;
165 | },
166 | });
167 | });
168 |
169 | $('#switch-theme').on('click', (e) => {
170 | const theme = e.target.checked ? 'solarized dark' : 'solarized';
171 | editor.setOption('theme', theme);
172 | astEditor.setOption('theme', theme);
173 | transformEditor.setOption('theme', theme);
174 | outputEditor.setOption('theme', theme);
175 |
176 | const $primarynav = document.getElementById('primary-nav');
177 |
178 | if (e.target.checked) {
179 | $primarynav.classList.replace('navbar-light', 'navbar-dark');
180 | $primarynav.classList.replace('bg-light', 'bg-dark');
181 | document.body.classList.add('dark-theme');
182 | } else {
183 | $primarynav.classList.replace('navbar-dark', 'navbar-light');
184 | $primarynav.classList.replace('bg-dark', 'bg-light');
185 | document.body.classList.remove('dark-theme');
186 | }
187 | });
188 |
189 | $(document).on('mouseover', '[role="treeitem"]', (event) => {
190 | const { beginPos, endPos } = event.currentTarget.dataset;
191 |
192 | // Clearing and pushing markers
193 | markers.forEach((marker) => marker.clear());
194 | if (beginPos && endPos) {
195 | const doc = editor.getDoc();
196 | const markFrom = doc.posFromIndex(beginPos);
197 | const markTo = doc.posFromIndex(endPos);
198 |
199 | const currentMark = editor.markText(markFrom, markTo, { className: 'styled-background' });
200 | markers.push(currentMark);
201 | }
202 |
203 | event.stopPropagation();
204 | });
205 |
206 | $(document).on('mouseleave', '[role="treeitem"]', () => {
207 | // Clearing and pushing markers
208 | markers.forEach((marker) => marker.clear());
209 | });
210 | });
211 |
--------------------------------------------------------------------------------
/app/javascript/packs/processorList.js:
--------------------------------------------------------------------------------
1 | const processorList = [
2 | 'arg',
3 | 'argument',
4 | 'back_ref',
5 | 'blockarg',
6 | 'casgn',
7 | 'const',
8 | 'cvar',
9 | 'cvasgn',
10 | 'def',
11 | 'defs',
12 | 'gvar',
13 | 'gvasgn',
14 | 'ivar',
15 | 'ivasgn',
16 | 'kwarg',
17 | 'kwoptarg',
18 | 'kwrestarg',
19 | 'lvar',
20 | 'lvasgn',
21 | 'nth_ref',
22 | 'op_asgn',
23 | 'optarg',
24 | 'procarg0',
25 | 'restarg',
26 | 'send',
27 | 'shadowarg',
28 | 'var',
29 | 'vasgn',
30 | ];
31 |
32 | export default processorList;
33 |
--------------------------------------------------------------------------------
/app/javascript/packs/treeLinks.js:
--------------------------------------------------------------------------------
1 | import TreeitemLink from './treeitemLinks';
2 | /*
3 | * This content is licensed according to the W3C Software License at
4 | * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
5 | *
6 | * File: TreeLinks.js
7 | *
8 | * Desc: Tree widget that implements ARIA Authoring Practices
9 | * for a tree being used as a file viewer
10 | */
11 |
12 | /**
13 | * ARIA Treeview example
14 | * @function onload
15 | * @desc after page has loaded initialize all treeitems based on the role=treeitem
16 | */
17 |
18 | window.addEventListener('load', () => {
19 |
20 |
21 | });
22 |
23 | /*
24 | * @constructor
25 | *
26 | * @desc
27 | * Tree item object for representing the state and user interactions for a
28 | * tree widget
29 | *
30 | * @param node
31 | * An element with the role=tree attribute
32 | */
33 |
34 | const TreeLinks = function (node) {
35 | // Check whether node is a DOM element
36 | if (typeof node !== 'object') {
37 | return;
38 | }
39 |
40 | this.domNode = node;
41 |
42 | this.treeitems = [];
43 | this.firstChars = [];
44 |
45 | this.firstTreeitem = null;
46 | this.lastTreeitem = null;
47 | };
48 |
49 | TreeLinks.prototype.init = function () {
50 | function findTreeitems(node, tree, group) {
51 | let elem = node.firstElementChild;
52 | let ti = group;
53 |
54 | while (elem) {
55 | if ((elem.tagName.toLowerCase() === 'li' && elem.firstElementChild.tagName.toLowerCase() === 'span') || elem.tagName.toLowerCase() === 'a') {
56 | ti = new TreeitemLink(elem, tree, group);
57 | ti.init();
58 | tree.treeitems.push(ti);
59 | tree.firstChars.push(ti.label.substring(0, 1).toLowerCase());
60 | }
61 |
62 | if (elem.firstElementChild) {
63 | findTreeitems(elem, tree, ti);
64 | }
65 |
66 | elem = elem.nextElementSibling;
67 | }
68 | }
69 |
70 | // initialize pop up menus
71 | if (!this.domNode.getAttribute('role')) {
72 | this.domNode.setAttribute('role', 'tree');
73 | }
74 |
75 | findTreeitems(this.domNode, this, false);
76 |
77 | this.updateVisibleTreeitems();
78 |
79 | this.firstTreeitem.domNode.tabIndex = 0;
80 | };
81 |
82 | TreeLinks.prototype.setFocusToItem = function (treeitem) {
83 | for (let i = 0; i < this.treeitems.length; i++) {
84 | const ti = this.treeitems[i];
85 |
86 | if (ti === treeitem) {
87 | ti.domNode.tabIndex = 0;
88 | ti.domNode.focus();
89 | } else {
90 | ti.domNode.tabIndex = -1;
91 | }
92 | }
93 | };
94 |
95 | TreeLinks.prototype.setFocusToNextItem = function (currentItem) {
96 | let nextItem = false;
97 |
98 | for (let i = (this.treeitems.length - 1); i >= 0; i--) {
99 | const ti = this.treeitems[i];
100 | if (ti === currentItem) {
101 | break;
102 | }
103 | if (ti.isVisible) {
104 | nextItem = ti;
105 | }
106 | }
107 |
108 | if (nextItem) {
109 | this.setFocusToItem(nextItem);
110 | }
111 | };
112 |
113 | TreeLinks.prototype.setFocusToPreviousItem = function (currentItem) {
114 | let prevItem = false;
115 |
116 | for (let i = 0; i < this.treeitems.length; i++) {
117 | const ti = this.treeitems[i];
118 | if (ti === currentItem) {
119 | break;
120 | }
121 | if (ti.isVisible) {
122 | prevItem = ti;
123 | }
124 | }
125 |
126 | if (prevItem) {
127 | this.setFocusToItem(prevItem);
128 | }
129 | };
130 |
131 | TreeLinks.prototype.setFocusToParentItem = function (currentItem) {
132 | if (currentItem.groupTreeitem) {
133 | this.setFocusToItem(currentItem.groupTreeitem);
134 | }
135 | };
136 |
137 | TreeLinks.prototype.setFocusToFirstItem = function () {
138 | this.setFocusToItem(this.firstTreeitem);
139 | };
140 |
141 | TreeLinks.prototype.setFocusToLastItem = function () {
142 | this.setFocusToItem(this.lastTreeitem);
143 | };
144 |
145 | TreeLinks.prototype.expandTreeitem = function (currentItem) {
146 | if (currentItem.isExpandable) {
147 | currentItem.domNode.setAttribute('aria-expanded', true);
148 | this.updateVisibleTreeitems();
149 | }
150 | };
151 |
152 | TreeLinks.prototype.expandAllSiblingItems = function (currentItem) {
153 | for (let i = 0; i < this.treeitems.length; i++) {
154 | const ti = this.treeitems[i];
155 |
156 | if ((ti.groupTreeitem === currentItem.groupTreeitem) && ti.isExpandable) {
157 | this.expandTreeitem(ti);
158 | }
159 | }
160 | };
161 |
162 | TreeLinks.prototype.collapseTreeitem = function (currentItem) {
163 | let groupTreeitem = false;
164 |
165 | if (currentItem.isExpanded()) {
166 | groupTreeitem = currentItem;
167 | } else {
168 | groupTreeitem = currentItem.groupTreeitem;
169 | }
170 |
171 | if (groupTreeitem) {
172 | groupTreeitem.domNode.setAttribute('aria-expanded', false);
173 | this.updateVisibleTreeitems();
174 | this.setFocusToItem(groupTreeitem);
175 | }
176 | };
177 |
178 | TreeLinks.prototype.updateVisibleTreeitems = function () {
179 | this.firstTreeitem = this.treeitems[0];
180 |
181 | for (let i = 0; i < this.treeitems.length; i++) {
182 | const ti = this.treeitems[i];
183 |
184 | let parent = ti.domNode.parentNode;
185 |
186 | ti.isVisible = true;
187 |
188 | while (parent && (parent !== this.domNode)) {
189 | if (parent.getAttribute('aria-expanded') == 'false') {
190 | ti.isVisible = false;
191 | }
192 | parent = parent.parentNode;
193 | }
194 |
195 | if (ti.isVisible) {
196 | this.lastTreeitem = ti;
197 | }
198 | }
199 | };
200 |
201 | TreeLinks.prototype.setFocusByFirstCharacter = function (currentItem, char) {
202 | let start;
203 | let index;
204 | char = char.toLowerCase();
205 |
206 | // Get start index for search based on position of currentItem
207 | start = this.treeitems.indexOf(currentItem) + 1;
208 | if (start === this.treeitems.length) {
209 | start = 0;
210 | }
211 |
212 | // Check remaining slots in the menu
213 | index = this.getIndexFirstChars(start, char);
214 |
215 | // If not found in remaining slots, check from beginning
216 | if (index === -1) {
217 | index = this.getIndexFirstChars(0, char);
218 | }
219 |
220 | // If match was found...
221 | if (index > -1) {
222 | this.setFocusToItem(this.treeitems[index]);
223 | }
224 | };
225 |
226 | TreeLinks.prototype.getIndexFirstChars = function (startIndex, char) {
227 | for (let i = startIndex; i < this.firstChars.length; i++) {
228 | if (this.treeitems[i].isVisible) {
229 | if (char === this.firstChars[i]) {
230 | return i;
231 | }
232 | }
233 | }
234 | return -1;
235 | };
236 |
237 |
238 | export default TreeLinks;
239 |
--------------------------------------------------------------------------------
/app/javascript/packs/treeitemLinks.js:
--------------------------------------------------------------------------------
1 | /*
2 | * This content is licensed according to the W3C Software License at
3 | * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
4 | *
5 | * File: TreeitemLink.js
6 | *
7 | * Desc: Treeitem widget that implements ARIA Authoring Practices
8 | * for a tree being used as a file viewer
9 | */
10 |
11 | /*
12 | * @constructor
13 | *
14 | * @desc
15 | * Treeitem object for representing the state and user interactions for a
16 | * treeItem widget
17 | *
18 | * @param node
19 | * An element with the role=tree attribute
20 | */
21 |
22 | const TreeitemLink = function (node, treeObj, group) {
23 | // Check whether node is a DOM element
24 | if (typeof node !== 'object') {
25 | return;
26 | }
27 |
28 | node.tabIndex = -1;
29 | this.tree = treeObj;
30 | this.groupTreeitem = group;
31 | this.domNode = node;
32 | this.label = node.textContent.trim();
33 | this.stopDefaultClick = false;
34 |
35 | if (node.getAttribute('aria-label')) {
36 | this.label = node.getAttribute('aria-label').trim();
37 | }
38 |
39 | this.isExpandable = false;
40 | this.isVisible = false;
41 | this.inGroup = false;
42 |
43 | if (group) {
44 | this.inGroup = true;
45 | }
46 |
47 | let elem = node.firstElementChild;
48 |
49 | while (elem) {
50 | if (elem.tagName.toLowerCase() == 'ul') {
51 | elem.setAttribute('role', 'group');
52 | this.isExpandable = true;
53 | break;
54 | }
55 |
56 | elem = elem.nextElementSibling;
57 | }
58 |
59 | this.keyCode = Object.freeze({
60 | RETURN: 13,
61 | SPACE: 32,
62 | PAGEUP: 33,
63 | PAGEDOWN: 34,
64 | END: 35,
65 | HOME: 36,
66 | LEFT: 37,
67 | UP: 38,
68 | RIGHT: 39,
69 | DOWN: 40,
70 | });
71 | };
72 |
73 | TreeitemLink.prototype.init = function () {
74 | this.domNode.tabIndex = -1;
75 |
76 | if (!this.domNode.getAttribute('role')) {
77 | this.domNode.setAttribute('role', 'treeitem');
78 | }
79 |
80 | this.domNode.addEventListener('keydown', this.handleKeydown.bind(this));
81 | this.domNode.addEventListener('click', this.handleClick.bind(this));
82 | this.domNode.addEventListener('focus', this.handleFocus.bind(this));
83 | this.domNode.addEventListener('blur', this.handleBlur.bind(this));
84 |
85 | /*
86 | if (this.isExpandable) {
87 | this.domNode.firstElementChild.addEventListener('mouseover', this.handleMouseOver.bind(this));
88 | this.domNode.firstElementChild.addEventListener('mouseout', this.handleMouseOut.bind(this));
89 | }
90 | else {
91 | this.domNode.addEventListener('mouseover', this.handleMouseOver.bind(this));
92 | this.domNode.addEventListener('mouseout', this.handleMouseOut.bind(this));
93 | }
94 | */
95 | };
96 |
97 | TreeitemLink.prototype.isExpanded = function () {
98 | if (this.isExpandable) {
99 | return this.domNode.getAttribute('aria-expanded') === 'true';
100 | }
101 |
102 | return false;
103 | };
104 |
105 | /* EVENT HANDLERS */
106 |
107 | TreeitemLink.prototype.handleKeydown = function (event) {
108 | const tgt = event.currentTarget;
109 | let flag = false;
110 | const char = event.key;
111 | let clickEvent;
112 |
113 | function isPrintableCharacter(str) {
114 | return str.length === 1 && str.match(/\S/);
115 | }
116 |
117 | function printableCharacter(item) {
118 | if (char == '*') {
119 | item.tree.expandAllSiblingItems(item);
120 | flag = true;
121 | } else if (isPrintableCharacter(char)) {
122 | item.tree.setFocusByFirstCharacter(item, char);
123 | flag = true;
124 | }
125 | }
126 |
127 | this.stopDefaultClick = false;
128 |
129 | if (event.altKey || event.ctrlKey || event.metaKey) {
130 | return;
131 | }
132 |
133 | if (event.shift) {
134 | if (event.keyCode == this.keyCode.SPACE || event.keyCode == this.keyCode.RETURN) {
135 | event.stopPropagation();
136 | this.stopDefaultClick = true;
137 | } else if (isPrintableCharacter(char)) {
138 | printableCharacter(this);
139 | }
140 | } else {
141 | switch (event.keyCode) {
142 | case this.keyCode.SPACE:
143 | case this.keyCode.RETURN:
144 | if (this.isExpandable) {
145 | if (this.isExpanded()) {
146 | this.tree.collapseTreeitem(this);
147 | } else {
148 | this.tree.expandTreeitem(this);
149 | }
150 | flag = true;
151 | } else {
152 | event.stopPropagation();
153 | this.stopDefaultClick = true;
154 | }
155 | break;
156 |
157 | case this.keyCode.UP:
158 | this.tree.setFocusToPreviousItem(this);
159 | flag = true;
160 | break;
161 |
162 | case this.keyCode.DOWN:
163 | this.tree.setFocusToNextItem(this);
164 | flag = true;
165 | break;
166 |
167 | case this.keyCode.RIGHT:
168 | if (this.isExpandable) {
169 | if (this.isExpanded()) {
170 | this.tree.setFocusToNextItem(this);
171 | } else {
172 | this.tree.expandTreeitem(this);
173 | }
174 | }
175 | flag = true;
176 | break;
177 |
178 | case this.keyCode.LEFT:
179 | if (this.isExpandable && this.isExpanded()) {
180 | this.tree.collapseTreeitem(this);
181 | flag = true;
182 | } else if (this.inGroup) {
183 | this.tree.setFocusToParentItem(this);
184 | flag = true;
185 | }
186 | break;
187 |
188 | case this.keyCode.HOME:
189 | this.tree.setFocusToFirstItem();
190 | flag = true;
191 | break;
192 |
193 | case this.keyCode.END:
194 | this.tree.setFocusToLastItem();
195 | flag = true;
196 | break;
197 |
198 | default:
199 | if (isPrintableCharacter(char)) {
200 | printableCharacter(this);
201 | }
202 | break;
203 | }
204 | }
205 |
206 | if (flag) {
207 | event.stopPropagation();
208 | event.preventDefault();
209 | }
210 | };
211 |
212 | TreeitemLink.prototype.handleClick = function (event) {
213 | // only process click events that directly happened on this treeitem
214 | if (event.target !== this.domNode && event.target !== this.domNode.firstElementChild) {
215 | return;
216 | }
217 |
218 | if (this.isExpandable) {
219 | if (this.isExpanded()) {
220 | this.tree.collapseTreeitem(this);
221 | } else {
222 | this.tree.expandTreeitem(this);
223 | }
224 | // event.stopPropagation();
225 | }
226 | };
227 |
228 | TreeitemLink.prototype.handleFocus = function (event) {
229 | let node = this.domNode;
230 | if (this.isExpandable) {
231 | node = node.firstElementChild;
232 | }
233 | node.classList.add('focus');
234 | };
235 |
236 | TreeitemLink.prototype.handleBlur = function (event) {
237 | let node = this.domNode;
238 | if (this.isExpandable) {
239 | node = node.firstElementChild;
240 | }
241 | node.classList.remove('focus');
242 | };
243 |
244 | TreeitemLink.prototype.handleMouseOver = function (event) {
245 | // event.currentTarget.classList.add('hover');
246 | console.log('hover');
247 | };
248 |
249 | TreeitemLink.prototype.handleMouseOut = function (event) {
250 | event.currentTarget.classList.remove('hover');
251 | };
252 |
253 |
254 | export default TreeitemLink;
255 |
--------------------------------------------------------------------------------
/app/javascript/packs/utils.js:
--------------------------------------------------------------------------------
1 | import processorList from './processorList';
2 | import TreeLinks from './treeLinks';
3 |
4 | // https://davidwalsh.name/javascript-debounce-function
5 | function debounce(func, wait, immediate) {
6 | let timeout;
7 | return function () { // eslint-disable-line
8 | const context = this; const
9 | args = arguments;// eslint-disable-line
10 | const later = function () { // eslint-disable-line
11 | timeout = null;
12 | if (!immediate) func.apply(context, args);
13 | };
14 | const callNow = immediate && !timeout;
15 | clearTimeout(timeout);
16 | timeout = setTimeout(later, wait);
17 | if (callNow) func.apply(context, args);
18 | };
19 | }
20 |
21 | function initTree() {
22 | const trees = document.querySelectorAll('[role="tree"]');
23 |
24 | for (let i = 0; i < trees.length; i++) {
25 | const t = new TreeLinks(trees[i]);
26 | t.init();
27 | }
28 | }
29 |
30 | function buildTreeView(ast) {
31 | const treeData = JSON.parse(ast);
32 | // console.log(treeData);
33 |
34 | function traverse(node) {
35 | let treeHtml = '';
36 |
37 | if (node) {
38 | const { location, type } = node;
39 | const {
40 | begin, end, expression, keyword, name, operator,
41 | } = location;
42 |
43 | if (expression) {
44 | const { begin_pos, end_pos } = expression; // eslint-disable-line
45 | const processorNode = (t) => (processorList.includes(t) ? `${t}: #on_${t}` : t);
46 | treeHtml += `
47 | ${processorNode(node.type)}`; // eslint-disable-line
48 | } else {
49 | treeHtml += `${node.type}`;
50 | }
51 |
52 | treeHtml += '';
53 |
54 | // Create type node
55 | if (type) {
56 | treeHtml += `- type: ${type}
`;
57 | }
58 |
59 | // Create location node
60 | if (location) {
61 | treeHtml += '- location
';
62 |
63 | const locationNode = (_node, _name) => {
64 | let str = '';
65 | const { begin_pos, end_pos } = _node;
66 | str += `- ${_name}`;
67 | str += '
';
68 | str += `- begin_pos: ${begin_pos}
`;
69 | str += `- end_pos: ${end_pos}
`;
70 | str += '
';
71 | str += ' ';
72 | return str;
73 | };
74 |
75 | // Create begin node
76 | if (begin) {
77 | treeHtml += locationNode(begin, 'begin');
78 | } else {
79 | treeHtml += '- begin: null
';
80 | }
81 |
82 | // Create end node
83 | if (end) {
84 | treeHtml += locationNode(end, 'end');
85 | } else {
86 | treeHtml += '- end: null
';
87 | }
88 |
89 | // Create expression node
90 | if (expression) {
91 | treeHtml += locationNode(expression, 'expression');
92 | }
93 |
94 | // Create keyword node
95 |
96 | if (keyword) {
97 | treeHtml += locationNode(keyword, 'keyword');
98 | }
99 |
100 | // Create name node
101 | if (name) {
102 | treeHtml += locationNode(name, 'name');
103 | }
104 |
105 | // Create operator node
106 | if (operator) {
107 | treeHtml += locationNode(operator, 'operator');
108 | } else {
109 | treeHtml += '- operator: null
';
110 | }
111 |
112 | treeHtml += '
';
113 | }
114 |
115 | if (node.children) {
116 | treeHtml += '- children: [ ]
';
117 | node.children.forEach((child) => {
118 | if (child == null) {
119 | treeHtml += '- nil
';
120 | } else if (node.type === 'sym') {
121 | treeHtml += `- :${child}
`;
122 | } else if (typeof child === 'object') {
123 | treeHtml += traverse(child);
124 | } else {
125 | treeHtml += `- ${child}
`;
126 | }
127 | });
128 |
129 | treeHtml += '
';
130 | }
131 | treeHtml += '
';
132 | treeHtml += '';
133 | }
134 |
135 | return treeHtml;
136 | }
137 |
138 | document.getElementById('ast-tree').innerHTML = traverse(treeData);
139 |
140 | initTree();
141 | }
142 |
143 | function indentCode(ed) {
144 | ed.setSelection({
145 | line: ed.firstLine(),
146 | ch: 0,
147 | sticky: null,
148 | }, {
149 | line: ed.lastLine(),
150 | ch: 0,
151 | sticky: null,
152 | },
153 | { scroll: false });
154 | // auto indent the selection
155 | ed.indentSelection('smart');
156 | ed.setCursor({ line: ed.firstLine(), ch: 0 });
157 | }
158 |
159 |
160 | export {
161 | debounce,
162 | buildTreeView,
163 | indentCode,
164 | };
165 |
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/views/ast/index.html.erb:
--------------------------------------------------------------------------------
1 | Ast#index
2 | Find me in app/views/ast/index.html.erb
3 |
--------------------------------------------------------------------------------
/app/views/gist/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
Import from Gist
3 |
9 |
--------------------------------------------------------------------------------
/app/views/gist/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= render 'shared/source-view' %>
5 |
6 |
7 | <%= render 'shared/tree-view' %>
8 |
9 |
10 |
11 |
12 |
13 |
14 | <%= render 'shared/transform-view' %>
15 |
16 |
17 | <%= render 'shared/output-view' %>
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
ruby-ast-explorer
5 | <%= csrf_meta_tags %>
6 | <%= csp_meta_tag %>
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
18 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
19 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
20 |
21 |
22 |
23 |
60 | <% flash.each do |key, value| %>
61 |
62 | <%= value %>
63 |
66 |
67 | <% end %>
68 | <%= yield %>
69 |
74 |
75 |
76 |
77 |
78 |
79 | <%#%>
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/app/views/shared/_output-view.html.erb:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/views/shared/_source-view.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/views/shared/_transform-view.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/views/shared/_tree-view.html.erb:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/views/welcome/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= render 'shared/source-view' %>
5 |
6 |
7 | <%= render 'shared/tree-view' %>
8 |
9 |
10 |
11 |
12 |
13 |
14 | <%= render 'shared/transform-view' %>
15 |
16 |
17 | <%= render 'shared/output-view' %>
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | var validEnv = ['development', 'test', 'production']
3 | var currentEnv = api.env()
4 | var isDevelopmentEnv = api.env('development')
5 | var isProductionEnv = api.env('production')
6 | var isTestEnv = api.env('test')
7 |
8 | if (!validEnv.includes(currentEnv)) {
9 | throw new Error(
10 | 'Please specify a valid `NODE_ENV` or ' +
11 | '`BABEL_ENV` environment variables. Valid values are "development", ' +
12 | '"test", and "production". Instead, received: ' +
13 | JSON.stringify(currentEnv) +
14 | '.'
15 | )
16 | }
17 |
18 | return {
19 | presets: [
20 | isTestEnv && [
21 | require('@babel/preset-env').default,
22 | {
23 | targets: {
24 | node: 'current'
25 | }
26 | }
27 | ],
28 | (isProductionEnv || isDevelopmentEnv) && [
29 | require('@babel/preset-env').default,
30 | {
31 | forceAllTransforms: true,
32 | useBuiltIns: 'entry',
33 | corejs: 3,
34 | modules: false,
35 | exclude: ['transform-typeof-symbol']
36 | }
37 | ]
38 | ].filter(Boolean),
39 | plugins: [
40 | require('babel-plugin-macros'),
41 | require('@babel/plugin-syntax-dynamic-import').default,
42 | isTestEnv && require('babel-plugin-dynamic-import-node'),
43 | require('@babel/plugin-transform-destructuring').default,
44 | [
45 | require('@babel/plugin-proposal-class-properties').default,
46 | {
47 | loose: true
48 | }
49 | ],
50 | [
51 | require('@babel/plugin-proposal-object-rest-spread').default,
52 | {
53 | useBuiltIns: true
54 | }
55 | ],
56 | [
57 | require('@babel/plugin-transform-runtime').default,
58 | {
59 | helpers: false,
60 | regenerator: true,
61 | corejs: false
62 | }
63 | ],
64 | [
65 | require('@babel/plugin-transform-regenerator').default,
66 | {
67 | async: false
68 | }
69 | ]
70 | ].filter(Boolean)
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../config/application', __dir__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a starting point to setup your application.
14 | # Add necessary setup steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | # puts "\n== Copying sample files =="
24 | # unless File.exist?('config/database.yml')
25 | # cp 'config/database.yml.sample', 'config/database.yml'
26 | # end
27 |
28 | puts "\n== Preparing database =="
29 | system! 'bin/rails db:setup'
30 |
31 | puts "\n== Removing old logs and tempfiles =="
32 | system! 'bin/rails log:clear tmp:clear'
33 |
34 | puts "\n== Restarting application server =="
35 | system! 'bin/rails restart'
36 | end
37 |
--------------------------------------------------------------------------------
/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a way to update your development environment automatically.
14 | # Add necessary update steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | puts "\n== Updating database =="
24 | system! 'bin/rails db:migrate'
25 |
26 | puts "\n== Removing old logs and tempfiles =="
27 | system! 'bin/rails log:clear tmp:clear'
28 |
29 | puts "\n== Restarting application server =="
30 | system! 'bin/rails restart'
31 | end
32 |
--------------------------------------------------------------------------------
/bin/webpack:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "rubygems"
11 | require "bundler/setup"
12 |
13 | require "webpacker"
14 | require "webpacker/webpack_runner"
15 |
16 | APP_ROOT = File.expand_path("..", __dir__)
17 | Dir.chdir(APP_ROOT) do
18 | Webpacker::WebpackRunner.run(ARGV)
19 | end
20 |
--------------------------------------------------------------------------------
/bin/webpack-dev-server:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "rubygems"
11 | require "bundler/setup"
12 |
13 | require "webpacker"
14 | require "webpacker/dev_server_runner"
15 |
16 | APP_ROOT = File.expand_path("..", __dir__)
17 | Dir.chdir(APP_ROOT) do
18 | Webpacker::DevServerRunner.run(ARGV)
19 | end
20 |
--------------------------------------------------------------------------------
/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_ROOT = File.expand_path('..', __dir__)
3 | Dir.chdir(APP_ROOT) do
4 | begin
5 | exec "yarnpkg", *ARGV
6 | rescue Errno::ENOENT
7 | $stderr.puts "Yarn executable was not detected in the system."
8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
9 | exit 1
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | module RubyAstExplorer
10 | class Application < Rails::Application
11 | # Initialize configuration defaults for originally generated Rails version.
12 | config.load_defaults 5.2
13 |
14 | # Settings in config/environments/* take precedence over those specified here.
15 | # Application configuration can go into files in config/initializers
16 | # -- all .rb files in that directory are automatically loaded after loading
17 | # the framework and any gems in your application.
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
5 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: ruby-ast-explorer_production
11 |
--------------------------------------------------------------------------------
/config/credentials.yml.enc:
--------------------------------------------------------------------------------
1 | WJxrdqspe0B9dpjlccb2ViPj/ByT9UmdqFaYKxd+OpY3o2OLvdmW8SUuDu5iPbNZIRgqFAtZuVjbaRCRaCXLg+Gs43T9epKAhZdaerLgW8pc2zUBFsGQaYJ/yVbWe6UECMPOOSUq3Kee00drOiIU+dCsHh2Woi1PgxPrtxkgneBVjzUtNi6bNKr3ipBk8QKh/VNOGnsLlN9ElbuJQPnFFrSDa7YW1gPgaUgHcMIpZPeKcb5AEfhSgiKKt1McJ7YW0V33aVbjb6+XwO04ETZyEtguCmTckk9tlBC/cxioGKUWN42T74ohCPFRnRx983YeqrWaZC8Yyt04Re6Acb8ZMUlt1jBA1Ow79JKHrTLvKVAzWhJD8VWZ7ap88+QCL5zWEKdHdlcsb/XWr/Q7yazIL4mFQ2zTwDJh3zUD--aLiUjnC9AP8kBxBB--bCXgpy0x0M8FAxN4LyOauw==
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | #
7 | default: &default
8 | adapter: postgresql
9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | #database: my_development_db
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: my_development_db
22 |
23 | production:
24 | <<: *default
25 | database: my_development_db
26 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports.
13 | config.consider_all_requests_local = true
14 |
15 | # Enable/disable caching. By default caching is disabled.
16 | # Run rails dev:cache to toggle caching.
17 | if Rails.root.join('tmp', 'caching-dev.txt').exist?
18 | config.action_controller.perform_caching = true
19 |
20 | config.cache_store = :memory_store
21 | config.public_file_server.headers = {
22 | 'Cache-Control' => "public, max-age=#{2.days.to_i}"
23 | }
24 | else
25 | config.action_controller.perform_caching = false
26 |
27 | config.cache_store = :null_store
28 | end
29 |
30 | # Store uploaded files on the local file system (see config/storage.yml for options)
31 | config.active_storage.service = :local
32 |
33 | # Don't care if the mailer can't send.
34 | config.action_mailer.raise_delivery_errors = false
35 |
36 | config.action_mailer.perform_caching = false
37 |
38 | # Print deprecation notices to the Rails logger.
39 | config.active_support.deprecation = :log
40 |
41 | # Raise an error on page load if there are pending migrations.
42 | config.active_record.migration_error = :page_load
43 |
44 | # Highlight code that triggered database queries in logs.
45 | config.active_record.verbose_query_logs = true
46 |
47 | # Debug mode disables concatenation and preprocessing of assets.
48 | # This option may cause significant delays in view rendering with a large
49 | # number of complex assets.
50 | config.assets.debug = true
51 |
52 | # Suppress logger output for asset requests.
53 | config.assets.quiet = true
54 |
55 | # Raises error for missing translations
56 | # config.action_view.raise_on_missing_translations = true
57 |
58 | # Use an evented file watcher to asynchronously detect changes in source code,
59 | # routes, locales, etc. This feature depends on the listen gem.
60 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
61 |
62 | ENV['GITHUB_KEY'] = '23b493911b3a796d843b'
63 | ENV['GITHUB_SECRET'] = 'a10756c33d3a06cd3b534d2aa4bb6aff93fa14c3'
64 | end
65 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
18 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
19 | # config.require_master_key = true
20 |
21 | # Disable serving static files from the `/public` folder by default since
22 | # Apache or NGINX already handles this.
23 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
24 |
25 | # Compress JavaScripts and CSS.
26 | #config.assets.js_compressor = :uglifier
27 | config.assets.js_compressor = Uglifier.new(:harmony => true)
28 | # config.assets.css_compressor = :sass
29 |
30 | # Do not fallback to assets pipeline if a precompiled asset is missed.
31 | config.assets.compile = false
32 |
33 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
34 |
35 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
36 | # config.action_controller.asset_host = 'http://assets.example.com'
37 |
38 | # Specifies the header that your server uses for sending files.
39 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
41 |
42 | # Store uploaded files on the local file system (see config/storage.yml for options)
43 | config.active_storage.service = :local
44 |
45 | # Mount Action Cable outside main process or domain
46 | # config.action_cable.mount_path = nil
47 | # config.action_cable.url = 'wss://example.com/cable'
48 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
49 |
50 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
51 | # config.force_ssl = true
52 |
53 | # Use the lowest log level to ensure availability of diagnostic information
54 | # when problems arise.
55 | config.log_level = :debug
56 |
57 | # Prepend all log lines with the following tags.
58 | config.log_tags = [ :request_id ]
59 |
60 | # Use a different cache store in production.
61 | # config.cache_store = :mem_cache_store
62 |
63 | # Use a real queuing backend for Active Job (and separate queues per environment)
64 | # config.active_job.queue_adapter = :resque
65 | # config.active_job.queue_name_prefix = "ruby-ast-explorer_#{Rails.env}"
66 |
67 | config.action_mailer.perform_caching = false
68 |
69 | # Ignore bad email addresses and do not raise email delivery errors.
70 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
71 | # config.action_mailer.raise_delivery_errors = false
72 |
73 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
74 | # the I18n.default_locale when a translation cannot be found).
75 | config.i18n.fallbacks = true
76 |
77 | # Send deprecation notices to registered listeners.
78 | config.active_support.deprecation = :notify
79 |
80 | # Use default logging formatter so that PID and timestamp are not suppressed.
81 | config.log_formatter = ::Logger::Formatter.new
82 |
83 | # Use a different logger for distributed setups.
84 | # require 'syslog/logger'
85 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
86 |
87 | if ENV["RAILS_LOG_TO_STDOUT"].present?
88 | logger = ActiveSupport::Logger.new(STDOUT)
89 | logger.formatter = config.log_formatter
90 | config.logger = ActiveSupport::TaggedLogging.new(logger)
91 | end
92 |
93 | # Do not dump schema after migrations.
94 | config.active_record.dump_schema_after_migration = false
95 |
96 | ENV['GITHUB_KEY'] = '79ad14545cc1877b4ed8'
97 | ENV['GITHUB_SECRET'] = '7e8de7e18eb6722c5bc9673b69b4cf7dfb5d6e86'
98 | end
99 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure public file server for tests with Cache-Control for performance.
16 | config.public_file_server.enabled = true
17 | config.public_file_server.headers = {
18 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
19 | }
20 |
21 | # Show full error reports and disable caching.
22 | config.consider_all_requests_local = true
23 | config.action_controller.perform_caching = false
24 |
25 | # Raise exceptions instead of rendering exception templates.
26 | config.action_dispatch.show_exceptions = false
27 |
28 | # Disable request forgery protection in test environment.
29 | config.action_controller.allow_forgery_protection = false
30 |
31 | # Store uploaded files on the local file system in a temporary directory
32 | config.active_storage.service = :test
33 |
34 | config.action_mailer.perform_caching = false
35 |
36 | # Tell Action Mailer not to deliver emails to the real world.
37 | # The :test delivery method accumulates sent emails in the
38 | # ActionMailer::Base.deliveries array.
39 | config.action_mailer.delivery_method = :test
40 |
41 | # Print deprecation notices to the stderr.
42 | config.active_support.deprecation = :stderr
43 |
44 | # Raises error for missing translations
45 | # config.action_view.raise_on_missing_translations = true
46 | end
47 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ActiveSupport::Reloader.to_prepare do
4 | # ApplicationController.renderer.defaults.merge!(
5 | # http_host: 'example.org',
6 | # https: false
7 | # )
8 | # end
9 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path.
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 | # Add Yarn node_modules folder to the asset load path.
9 | Rails.application.config.assets.paths << Rails.root.join('node_modules')
10 |
11 | # Precompile additional assets.
12 | # application.js, application.css, and all non-JS/CSS in the app/assets
13 | # folder are already added.
14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
15 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide content security policy
4 | # For further information see the following documentation
5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
6 |
7 | # Rails.application.config.content_security_policy do |policy|
8 | # policy.default_src :self, :https
9 | # policy.font_src :self, :https, :data
10 | # policy.img_src :self, :https, :data
11 | # policy.object_src :none
12 | # policy.script_src :self, :https
13 | # policy.style_src :self, :https
14 |
15 | # # Specify URI for violation reports
16 | # # policy.report_uri "/csp-violation-report-endpoint"
17 | # end
18 |
19 | # If you are using UJS then enable automatic nonce generation
20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
21 |
22 | # Report CSP violations to a specified URI
23 | # For further information see the following documentation:
24 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
25 | # Rails.application.config.content_security_policy_report_only = true
26 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Specify a serializer for the signed and encrypted cookie jars.
4 | # Valid options are :json, :marshal, and :hybrid.
5 | Rails.application.config.action_dispatch.cookies_serializer = :json
6 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/config/initializers/omniauth.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # config/initializers/omniauth.rb
4 | Rails.application.config.middleware.use OmniAuth::Builder do
5 | provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'],
6 | scope: 'user:email,user:follow,gist'
7 | end
8 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json]
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | hello: "Hello world"
34 |
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | # Puma can serve each request in a thread from an internal thread pool.
2 | # The `threads` method setting takes two numbers: a minimum and maximum.
3 | # Any libraries that use thread pools should be configured to match
4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
5 | # and maximum; this matches the default thread size of Active Record.
6 | #
7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8 | threads threads_count, threads_count
9 |
10 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11 | #
12 | port ENV.fetch("PORT") { 3000 }
13 |
14 | # Specifies the `environment` that Puma will run in.
15 | #
16 | environment ENV.fetch("RAILS_ENV") { "development" }
17 |
18 | # Specifies the number of `workers` to boot in clustered mode.
19 | # Workers are forked webserver processes. If using threads and workers together
20 | # the concurrency of the application would be max `threads` * `workers`.
21 | # Workers do not work on JRuby or Windows (both of which do not support
22 | # processes).
23 | #
24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
25 |
26 | # Use the `preload_app!` method when specifying a `workers` number.
27 | # This directive tells Puma to first boot the application and load code
28 | # before forking the application. This takes advantage of Copy On Write
29 | # process behavior so workers use less memory.
30 | #
31 | # preload_app!
32 |
33 | # Allow puma to be restarted by `rails restart` command.
34 | plugin :tmp_restart
35 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | get 'gist/show'
3 | get 'ast/index'
4 | resources :ast
5 | resources :gist
6 | get 'welcome/index'
7 | post 'ast/gist' => 'ast#gist'
8 | get "/auth/github/callback" => "sessions#create"
9 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
10 | root 'welcome#index'
11 | end
12 |
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | %w[
2 | .ruby-version
3 | .rbenv-vars
4 | tmp/restart.txt
5 | tmp/caching-dev.txt
6 | ].each { |path| Spring.watch(path) }
7 |
--------------------------------------------------------------------------------
/config/storage.yml:
--------------------------------------------------------------------------------
1 | test:
2 | service: Disk
3 | root: <%= Rails.root.join("tmp/storage") %>
4 |
5 | local:
6 | service: Disk
7 | root: <%= Rails.root.join("storage") %>
8 |
9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10 | # amazon:
11 | # service: S3
12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14 | # region: us-east-1
15 | # bucket: your_own_bucket
16 |
17 | # Remember not to checkin your GCS keyfile to a repository
18 | # google:
19 | # service: GCS
20 | # project: your_project
21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22 | # bucket: your_own_bucket
23 |
24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25 | # microsoft:
26 | # service: AzureStorage
27 | # storage_account_name: your_account_name
28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29 | # container: your_container_name
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/config/webpack/development.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development'
2 |
3 | const environment = require('./environment')
4 |
5 | module.exports = environment.toWebpackConfig()
6 |
--------------------------------------------------------------------------------
/config/webpack/environment.js:
--------------------------------------------------------------------------------
1 | const { environment } = require('@rails/webpacker')
2 |
3 | module.exports = environment
4 |
--------------------------------------------------------------------------------
/config/webpack/production.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'production'
2 |
3 | const environment = require('./environment')
4 |
5 | module.exports = environment.toWebpackConfig()
6 |
--------------------------------------------------------------------------------
/config/webpack/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development'
2 |
3 | const environment = require('./environment')
4 |
5 | module.exports = environment.toWebpackConfig()
6 |
--------------------------------------------------------------------------------
/config/webpacker.yml:
--------------------------------------------------------------------------------
1 | # Note: You must restart bin/webpack-dev-server for changes to take effect
2 |
3 | default: &default
4 | source_path: app/javascript
5 | source_entry_path: packs
6 | public_root_path: public
7 | public_output_path: packs
8 | cache_path: tmp/cache/webpacker
9 | check_yarn_integrity: false
10 | webpack_compile_output: false
11 |
12 | # Additional paths webpack should lookup modules
13 | # ['app/assets', 'engine/foo/app/assets']
14 | resolved_paths: []
15 |
16 | # Reload manifest.json on all requests so we reload latest compiled packs
17 | cache_manifest: false
18 |
19 | # Extract and emit a css file
20 | extract_css: false
21 |
22 | static_assets_extensions:
23 | - .jpg
24 | - .jpeg
25 | - .png
26 | - .gif
27 | - .tiff
28 | - .ico
29 | - .svg
30 | - .eot
31 | - .otf
32 | - .ttf
33 | - .woff
34 | - .woff2
35 |
36 | extensions:
37 | - .mjs
38 | - .js
39 | - .sass
40 | - .scss
41 | - .css
42 | - .module.sass
43 | - .module.scss
44 | - .module.css
45 | - .png
46 | - .svg
47 | - .gif
48 | - .jpeg
49 | - .jpg
50 |
51 | development:
52 | <<: *default
53 | compile: true
54 |
55 | # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
56 | check_yarn_integrity: true
57 |
58 | # Reference: https://webpack.js.org/configuration/dev-server/
59 | dev_server:
60 | https: false
61 | host: localhost
62 | port: 3035
63 | public: localhost:3035
64 | hmr: false
65 | # Inline should be set to true if using HMR
66 | inline: true
67 | overlay: true
68 | compress: true
69 | disable_host_check: true
70 | use_local_ip: false
71 | quiet: false
72 | headers:
73 | 'Access-Control-Allow-Origin': '*'
74 | watch_options:
75 | ignored: '**/node_modules/**'
76 |
77 |
78 | test:
79 | <<: *default
80 | compile: true
81 |
82 | # Compile test packs to a separate directory
83 | public_output_path: packs-test
84 |
85 | production:
86 | <<: *default
87 |
88 | # Production depends on precompilation of packs prior to booting for performance.
89 | compile: true
90 |
91 | # Extract and emit a css file
92 | extract_css: true
93 |
94 | # Cache manifest.json for performance
95 | cache_manifest: true
96 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
7 | # Character.create(name: 'Luke', movie: movies.first)
8 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/lib/tasks/.keep
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/log/.keep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ruby-ast-explorer",
3 | "private": true,
4 | "dependencies": {
5 | "@rails/webpacker": "^4.0.7"
6 | },
7 | "devDependencies": {
8 | "eslint": "^6.3.0",
9 | "eslint-config-airbnb-base": "^14.0.0",
10 | "eslint-plugin-import": "^2.18.2",
11 | "webpack-dev-server": "^3.8.0"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('postcss-import'),
4 | require('postcss-flexbugs-fixes'),
5 | require('postcss-preset-env')({
6 | autoprefixer: {
7 | flexbox: 'no-2009'
8 | },
9 | stage: 3
10 | })
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | direction: ltr;
9 | }
10 |
11 | /* PADDING */
12 |
13 | .CodeMirror-lines {
14 | padding: 4px 0; /* Vertical padding around content */
15 | }
16 | .CodeMirror pre {
17 | padding: 0 4px; /* Horizontal padding of content */
18 | }
19 |
20 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
21 | background-color: white; /* The little square between H and V scrollbars */
22 | }
23 |
24 | /* GUTTER */
25 |
26 | .CodeMirror-gutters {
27 | border-right: 1px solid #ddd;
28 | background-color: #f7f7f7;
29 | white-space: nowrap;
30 | }
31 | .CodeMirror-linenumbers {}
32 | .CodeMirror-linenumber {
33 | padding: 0 3px 0 5px;
34 | min-width: 20px;
35 | text-align: right;
36 | color: #999;
37 | white-space: nowrap;
38 | }
39 |
40 | .CodeMirror-guttermarker { color: black; }
41 | .CodeMirror-guttermarker-subtle { color: #999; }
42 |
43 | /* CURSOR */
44 |
45 | .CodeMirror-cursor {
46 | border-left: 1px solid black;
47 | border-right: none;
48 | width: 0;
49 | }
50 | /* Shown when moving in bi-directional text */
51 | .CodeMirror div.CodeMirror-secondarycursor {
52 | border-left: 1px solid silver;
53 | }
54 | .cm-fat-cursor .CodeMirror-cursor {
55 | width: auto;
56 | border: 0 !important;
57 | background: #7e7;
58 | }
59 | .cm-fat-cursor div.CodeMirror-cursors {
60 | z-index: 1;
61 | }
62 | .cm-fat-cursor-mark {
63 | background-color: rgba(20, 255, 20, 0.5);
64 | -webkit-animation: blink 1.06s steps(1) infinite;
65 | -moz-animation: blink 1.06s steps(1) infinite;
66 | animation: blink 1.06s steps(1) infinite;
67 | }
68 | .cm-animate-fat-cursor {
69 | width: auto;
70 | border: 0;
71 | -webkit-animation: blink 1.06s steps(1) infinite;
72 | -moz-animation: blink 1.06s steps(1) infinite;
73 | animation: blink 1.06s steps(1) infinite;
74 | background-color: #7e7;
75 | }
76 | @-moz-keyframes blink {
77 | 0% {}
78 | 50% { background-color: transparent; }
79 | 100% {}
80 | }
81 | @-webkit-keyframes blink {
82 | 0% {}
83 | 50% { background-color: transparent; }
84 | 100% {}
85 | }
86 | @keyframes blink {
87 | 0% {}
88 | 50% { background-color: transparent; }
89 | 100% {}
90 | }
91 |
92 | /* Can style cursor different in overwrite (non-insert) mode */
93 | .CodeMirror-overwrite .CodeMirror-cursor {}
94 |
95 | .cm-tab { display: inline-block; text-decoration: inherit; }
96 |
97 | .CodeMirror-rulers {
98 | position: absolute;
99 | left: 0; right: 0; top: -50px; bottom: -20px;
100 | overflow: hidden;
101 | }
102 | .CodeMirror-ruler {
103 | border-left: 1px solid #ccc;
104 | top: 0; bottom: 0;
105 | position: absolute;
106 | }
107 |
108 | /* DEFAULT THEME */
109 |
110 | .cm-s-default .cm-header {color: blue;}
111 | .cm-s-default .cm-quote {color: #090;}
112 | .cm-negative {color: #d44;}
113 | .cm-positive {color: #292;}
114 | .cm-header, .cm-strong {font-weight: bold;}
115 | .cm-em {font-style: italic;}
116 | .cm-link {text-decoration: underline;}
117 | .cm-strikethrough {text-decoration: line-through;}
118 |
119 | .cm-s-default .cm-keyword {color: #708;}
120 | .cm-s-default .cm-atom {color: #219;}
121 | .cm-s-default .cm-number {color: #164;}
122 | .cm-s-default .cm-def {color: #00f;}
123 | .cm-s-default .cm-variable,
124 | .cm-s-default .cm-punctuation,
125 | .cm-s-default .cm-property,
126 | .cm-s-default .cm-operator {}
127 | .cm-s-default .cm-variable-2 {color: #05a;}
128 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
129 | .cm-s-default .cm-comment {color: #a50;}
130 | .cm-s-default .cm-string {color: #a11;}
131 | .cm-s-default .cm-string-2 {color: #f50;}
132 | .cm-s-default .cm-meta {color: #555;}
133 | .cm-s-default .cm-qualifier {color: #555;}
134 | .cm-s-default .cm-builtin {color: #30a;}
135 | .cm-s-default .cm-bracket {color: #997;}
136 | .cm-s-default .cm-tag {color: #170;}
137 | .cm-s-default .cm-attribute {color: #00c;}
138 | .cm-s-default .cm-hr {color: #999;}
139 | .cm-s-default .cm-link {color: #00c;}
140 |
141 | .cm-s-default .cm-error {color: #f00;}
142 | .cm-invalidchar {color: #f00;}
143 |
144 | .CodeMirror-composing { border-bottom: 2px solid; }
145 |
146 | /* Default styles for common addons */
147 |
148 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
149 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
150 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
151 | .CodeMirror-activeline-background {background: #e8f2ff;}
152 |
153 | /* STOP */
154 |
155 | /* The rest of this file contains styles related to the mechanics of
156 | the editor. You probably shouldn't touch them. */
157 |
158 | .CodeMirror {
159 | position: relative;
160 | overflow: hidden;
161 | background: white;
162 | }
163 |
164 | .CodeMirror-scroll {
165 | overflow: scroll !important; /* Things will break if this is overridden */
166 | /* 30px is the magic margin used to hide the element's real scrollbars */
167 | /* See overflow: hidden in .CodeMirror */
168 | margin-bottom: -30px; margin-right: -30px;
169 | padding-bottom: 30px;
170 | height: 100%;
171 | outline: none; /* Prevent dragging from highlighting the element */
172 | position: relative;
173 | }
174 | .CodeMirror-sizer {
175 | position: relative;
176 | border-right: 30px solid transparent;
177 | }
178 |
179 | /* The fake, visible scrollbars. Used to force redraw during scrolling
180 | before actual scrolling happens, thus preventing shaking and
181 | flickering artifacts. */
182 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
183 | position: absolute;
184 | z-index: 6;
185 | display: none;
186 | }
187 | .CodeMirror-vscrollbar {
188 | right: 0; top: 0;
189 | overflow-x: hidden;
190 | overflow-y: scroll;
191 | }
192 | .CodeMirror-hscrollbar {
193 | bottom: 0; left: 0;
194 | overflow-y: hidden;
195 | overflow-x: scroll;
196 | }
197 | .CodeMirror-scrollbar-filler {
198 | right: 0; bottom: 0;
199 | }
200 | .CodeMirror-gutter-filler {
201 | left: 0; bottom: 0;
202 | }
203 |
204 | .CodeMirror-gutters {
205 | position: absolute; left: 0; top: 0;
206 | min-height: 100%;
207 | z-index: 3;
208 | }
209 | .CodeMirror-gutter {
210 | white-space: normal;
211 | height: 100%;
212 | display: inline-block;
213 | vertical-align: top;
214 | margin-bottom: -30px;
215 | }
216 | .CodeMirror-gutter-wrapper {
217 | position: absolute;
218 | z-index: 4;
219 | background: none !important;
220 | border: none !important;
221 | }
222 | .CodeMirror-gutter-background {
223 | position: absolute;
224 | top: 0; bottom: 0;
225 | z-index: 4;
226 | }
227 | .CodeMirror-gutter-elt {
228 | position: absolute;
229 | cursor: default;
230 | z-index: 4;
231 | }
232 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent }
233 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
234 |
235 | .CodeMirror-lines {
236 | cursor: text;
237 | min-height: 1px; /* prevents collapsing before first draw */
238 | }
239 | .CodeMirror pre {
240 | /* Reset some styles that the rest of the page might have set */
241 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
242 | border-width: 0;
243 | background: transparent;
244 | font-family: inherit;
245 | font-size: inherit;
246 | margin: 0;
247 | white-space: pre;
248 | word-wrap: normal;
249 | line-height: inherit;
250 | color: inherit;
251 | z-index: 2;
252 | position: relative;
253 | overflow: visible;
254 | -webkit-tap-highlight-color: transparent;
255 | -webkit-font-variant-ligatures: contextual;
256 | font-variant-ligatures: contextual;
257 | }
258 | .CodeMirror-wrap pre {
259 | word-wrap: break-word;
260 | white-space: pre-wrap;
261 | word-break: normal;
262 | }
263 |
264 | .CodeMirror-linebackground {
265 | position: absolute;
266 | left: 0; right: 0; top: 0; bottom: 0;
267 | z-index: 0;
268 | }
269 |
270 | .CodeMirror-linewidget {
271 | position: relative;
272 | z-index: 2;
273 | padding: 0.1px; /* Force widget margins to stay inside of the container */
274 | }
275 |
276 | .CodeMirror-widget {}
277 |
278 | .CodeMirror-rtl pre { direction: rtl; }
279 |
280 | .CodeMirror-code {
281 | outline: none;
282 | }
283 |
284 | /* Force content-box sizing for the elements where we expect it */
285 | .CodeMirror-scroll,
286 | .CodeMirror-sizer,
287 | .CodeMirror-gutter,
288 | .CodeMirror-gutters,
289 | .CodeMirror-linenumber {
290 | -moz-box-sizing: content-box;
291 | box-sizing: content-box;
292 | }
293 |
294 | .CodeMirror-measure {
295 | position: absolute;
296 | width: 100%;
297 | height: 0;
298 | overflow: hidden;
299 | visibility: hidden;
300 | }
301 |
302 | .CodeMirror-cursor {
303 | position: absolute;
304 | pointer-events: none;
305 | }
306 | .CodeMirror-measure pre { position: static; }
307 |
308 | div.CodeMirror-cursors {
309 | visibility: hidden;
310 | position: relative;
311 | z-index: 3;
312 | }
313 | div.CodeMirror-dragcursors {
314 | visibility: visible;
315 | }
316 |
317 | .CodeMirror-focused div.CodeMirror-cursors {
318 | visibility: visible;
319 | }
320 |
321 | .CodeMirror-selected { background: #d9d9d9; }
322 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
323 | .CodeMirror-crosshair { cursor: crosshair; }
324 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
325 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
326 |
327 | .cm-searching {
328 | background-color: #ffa;
329 | background-color: rgba(255, 255, 0, .4);
330 | }
331 |
332 | /* Used to force a border model for a node */
333 | .cm-force-border { padding-right: .1px; }
334 |
335 | @media print {
336 | /* Hide the cursor when printing */
337 | .CodeMirror div.CodeMirror-cursors {
338 | visibility: hidden;
339 | }
340 | }
341 |
342 | /* See issue #2901 */
343 | .cm-tab-wrap-hack:after { content: ''; }
344 |
345 | /* Help users use markselection to safely style text background */
346 | span.CodeMirror-selectedtext { background: none; }
347 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/public/favicon.ico
--------------------------------------------------------------------------------
/public/images/down-arrow-brown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/public/images/down-arrow-brown.png
--------------------------------------------------------------------------------
/public/images/right-arrow-brown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/public/images/right-arrow-brown.png
--------------------------------------------------------------------------------
/public/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /* Document
4 | ========================================================================== */
5 |
6 | /**
7 | * 1. Correct the line height in all browsers.
8 | * 2. Prevent adjustments of font size after orientation changes in iOS.
9 | */
10 |
11 | html {
12 | line-height: 1.15; /* 1 */
13 | -webkit-text-size-adjust: 100%; /* 2 */
14 | }
15 |
16 | /* Sections
17 | ========================================================================== */
18 |
19 | /**
20 | * Remove the margin in all browsers.
21 | */
22 |
23 | body {
24 | margin: 0;
25 | }
26 |
27 | /**
28 | * Render the `main` element consistently in IE.
29 | */
30 |
31 | main {
32 | display: block;
33 | }
34 |
35 | /**
36 | * Correct the font size and margin on `h1` elements within `section` and
37 | * `article` contexts in Chrome, Firefox, and Safari.
38 | */
39 |
40 | h1 {
41 | font-size: 2em;
42 | margin: 0.67em 0;
43 | }
44 |
45 | /* Grouping content
46 | ========================================================================== */
47 |
48 | /**
49 | * 1. Add the correct box sizing in Firefox.
50 | * 2. Show the overflow in Edge and IE.
51 | */
52 |
53 | hr {
54 | box-sizing: content-box; /* 1 */
55 | height: 0; /* 1 */
56 | overflow: visible; /* 2 */
57 | }
58 |
59 | /**
60 | * 1. Correct the inheritance and scaling of font size in all browsers.
61 | * 2. Correct the odd `em` font sizing in all browsers.
62 | */
63 |
64 | pre {
65 | font-family: monospace, monospace; /* 1 */
66 | font-size: 1em; /* 2 */
67 | }
68 |
69 | /* Text-level semantics
70 | ========================================================================== */
71 |
72 | /**
73 | * Remove the gray background on active links in IE 10.
74 | */
75 |
76 | a {
77 | background-color: transparent;
78 | }
79 |
80 | /**
81 | * 1. Remove the bottom border in Chrome 57-
82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
83 | */
84 |
85 | abbr[title] {
86 | border-bottom: none; /* 1 */
87 | text-decoration: underline; /* 2 */
88 | text-decoration: underline dotted; /* 2 */
89 | }
90 |
91 | /**
92 | * Add the correct font weight in Chrome, Edge, and Safari.
93 | */
94 |
95 | b,
96 | strong {
97 | font-weight: bolder;
98 | }
99 |
100 | /**
101 | * 1. Correct the inheritance and scaling of font size in all browsers.
102 | * 2. Correct the odd `em` font sizing in all browsers.
103 | */
104 |
105 | code,
106 | kbd,
107 | samp {
108 | font-family: monospace, monospace; /* 1 */
109 | font-size: 1em; /* 2 */
110 | }
111 |
112 | /**
113 | * Add the correct font size in all browsers.
114 | */
115 |
116 | small {
117 | font-size: 80%;
118 | }
119 |
120 | /**
121 | * Prevent `sub` and `sup` elements from affecting the line height in
122 | * all browsers.
123 | */
124 |
125 | sub,
126 | sup {
127 | font-size: 75%;
128 | line-height: 0;
129 | position: relative;
130 | vertical-align: baseline;
131 | }
132 |
133 | sub {
134 | bottom: -0.25em;
135 | }
136 |
137 | sup {
138 | top: -0.5em;
139 | }
140 |
141 | /* Embedded content
142 | ========================================================================== */
143 |
144 | /**
145 | * Remove the border on images inside links in IE 10.
146 | */
147 |
148 | img {
149 | border-style: none;
150 | }
151 |
152 | /* Forms
153 | ========================================================================== */
154 |
155 | /**
156 | * 1. Change the font styles in all browsers.
157 | * 2. Remove the margin in Firefox and Safari.
158 | */
159 |
160 | button,
161 | input,
162 | optgroup,
163 | select,
164 | textarea {
165 | font-family: inherit; /* 1 */
166 | font-size: 100%; /* 1 */
167 | line-height: 1.15; /* 1 */
168 | margin: 0; /* 2 */
169 | }
170 |
171 | /**
172 | * Show the overflow in IE.
173 | * 1. Show the overflow in Edge.
174 | */
175 |
176 | button,
177 | input { /* 1 */
178 | overflow: visible;
179 | }
180 |
181 | /**
182 | * Remove the inheritance of text transform in Edge, Firefox, and IE.
183 | * 1. Remove the inheritance of text transform in Firefox.
184 | */
185 |
186 | button,
187 | select { /* 1 */
188 | text-transform: none;
189 | }
190 |
191 | /**
192 | * Correct the inability to style clickable types in iOS and Safari.
193 | */
194 |
195 | button,
196 | [type="button"],
197 | [type="reset"],
198 | [type="submit"] {
199 | -webkit-appearance: button;
200 | }
201 |
202 | /**
203 | * Remove the inner border and padding in Firefox.
204 | */
205 |
206 | button::-moz-focus-inner,
207 | [type="button"]::-moz-focus-inner,
208 | [type="reset"]::-moz-focus-inner,
209 | [type="submit"]::-moz-focus-inner {
210 | border-style: none;
211 | padding: 0;
212 | }
213 |
214 | /**
215 | * Restore the focus styles unset by the previous rule.
216 | */
217 |
218 | button:-moz-focusring,
219 | [type="button"]:-moz-focusring,
220 | [type="reset"]:-moz-focusring,
221 | [type="submit"]:-moz-focusring {
222 | outline: 1px dotted ButtonText;
223 | }
224 |
225 | /**
226 | * Correct the padding in Firefox.
227 | */
228 |
229 | fieldset {
230 | padding: 0.35em 0.75em 0.625em;
231 | }
232 |
233 | /**
234 | * 1. Correct the text wrapping in Edge and IE.
235 | * 2. Correct the color inheritance from `fieldset` elements in IE.
236 | * 3. Remove the padding so developers are not caught out when they zero out
237 | * `fieldset` elements in all browsers.
238 | */
239 |
240 | legend {
241 | box-sizing: border-box; /* 1 */
242 | color: inherit; /* 2 */
243 | display: table; /* 1 */
244 | max-width: 100%; /* 1 */
245 | padding: 0; /* 3 */
246 | white-space: normal; /* 1 */
247 | }
248 |
249 | /**
250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera.
251 | */
252 |
253 | progress {
254 | vertical-align: baseline;
255 | }
256 |
257 | /**
258 | * Remove the default vertical scrollbar in IE 10+.
259 | */
260 |
261 | textarea {
262 | overflow: auto;
263 | }
264 |
265 | /**
266 | * 1. Add the correct box sizing in IE 10.
267 | * 2. Remove the padding in IE 10.
268 | */
269 |
270 | [type="checkbox"],
271 | [type="radio"] {
272 | box-sizing: border-box; /* 1 */
273 | padding: 0; /* 2 */
274 | }
275 |
276 | /**
277 | * Correct the cursor style of increment and decrement buttons in Chrome.
278 | */
279 |
280 | [type="number"]::-webkit-inner-spin-button,
281 | [type="number"]::-webkit-outer-spin-button {
282 | height: auto;
283 | }
284 |
285 | /**
286 | * 1. Correct the odd appearance in Chrome and Safari.
287 | * 2. Correct the outline style in Safari.
288 | */
289 |
290 | [type="search"] {
291 | -webkit-appearance: textfield; /* 1 */
292 | outline-offset: -2px; /* 2 */
293 | }
294 |
295 | /**
296 | * Remove the inner padding in Chrome and Safari on macOS.
297 | */
298 |
299 | [type="search"]::-webkit-search-decoration {
300 | -webkit-appearance: none;
301 | }
302 |
303 | /**
304 | * 1. Correct the inability to style clickable types in iOS and Safari.
305 | * 2. Change font properties to `inherit` in Safari.
306 | */
307 |
308 | ::-webkit-file-upload-button {
309 | -webkit-appearance: button; /* 1 */
310 | font: inherit; /* 2 */
311 | }
312 |
313 | /* Interactive
314 | ========================================================================== */
315 |
316 | /*
317 | * Add the correct display in Edge, IE 10+, and Firefox.
318 | */
319 |
320 | details {
321 | display: block;
322 | }
323 |
324 | /*
325 | * Add the correct display in all browsers.
326 | */
327 |
328 | summary {
329 | display: list-item;
330 | }
331 |
332 | /* Misc
333 | ========================================================================== */
334 |
335 | /**
336 | * Add the correct display in IE 10+.
337 | */
338 |
339 | template {
340 | display: none;
341 | }
342 |
343 | /**
344 | * Add the correct display in IE 10.
345 | */
346 |
347 | [hidden] {
348 | display: none;
349 | }
350 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/public/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/public/screenshot.png
--------------------------------------------------------------------------------
/public/solarized.css:
--------------------------------------------------------------------------------
1 | /*
2 | Solarized theme for code-mirror
3 | http://ethanschoonover.com/solarized
4 | */
5 |
6 | /*
7 | Solarized color palette
8 | http://ethanschoonover.com/solarized/img/solarized-palette.png
9 | */
10 |
11 | .solarized.base03 { color: #002b36; }
12 | .solarized.base02 { color: #073642; }
13 | .solarized.base01 { color: #586e75; }
14 | .solarized.base00 { color: #657b83; }
15 | .solarized.base0 { color: #839496; }
16 | .solarized.base1 { color: #93a1a1; }
17 | .solarized.base2 { color: #eee8d5; }
18 | .solarized.base3 { color: #fdf6e3; }
19 | .solarized.solar-yellow { color: #b58900; }
20 | .solarized.solar-orange { color: #cb4b16; }
21 | .solarized.solar-red { color: #dc322f; }
22 | .solarized.solar-magenta { color: #d33682; }
23 | .solarized.solar-violet { color: #6c71c4; }
24 | .solarized.solar-blue { color: #268bd2; }
25 | .solarized.solar-cyan { color: #2aa198; }
26 | .solarized.solar-green { color: #859900; }
27 |
28 | /* Color scheme for code-mirror */
29 |
30 | .cm-s-solarized {
31 | line-height: 1.45em;
32 | color-profile: sRGB;
33 | rendering-intent: auto;
34 | }
35 | .cm-s-solarized.cm-s-dark {
36 | color: #839496;
37 | background-color: #002b36;
38 | text-shadow: #002b36 0 1px;
39 | }
40 | .cm-s-solarized.cm-s-light {
41 | background-color: #fdf6e3;
42 | color: #657b83;
43 | text-shadow: #eee8d5 0 1px;
44 | }
45 |
46 | .cm-s-solarized .CodeMirror-widget {
47 | text-shadow: none;
48 | }
49 |
50 | .cm-s-solarized .cm-header { color: #586e75; }
51 | .cm-s-solarized .cm-quote { color: #93a1a1; }
52 |
53 | .cm-s-solarized .cm-keyword { color: #cb4b16; }
54 | .cm-s-solarized .cm-atom { color: #d33682; }
55 | .cm-s-solarized .cm-number { color: #d33682; }
56 | .cm-s-solarized .cm-def { color: #2aa198; }
57 |
58 | .cm-s-solarized .cm-variable { color: #839496; }
59 | .cm-s-solarized .cm-variable-2 { color: #b58900; }
60 | .cm-s-solarized .cm-variable-3, .cm-s-solarized .cm-type { color: #6c71c4; }
61 |
62 | .cm-s-solarized .cm-property { color: #2aa198; }
63 | .cm-s-solarized .cm-operator { color: #6c71c4; }
64 |
65 | .cm-s-solarized .cm-comment { color: #586e75; font-style:italic; }
66 |
67 | .cm-s-solarized .cm-string { color: #859900; }
68 | .cm-s-solarized .cm-string-2 { color: #b58900; }
69 |
70 | .cm-s-solarized .cm-meta { color: #859900; }
71 | .cm-s-solarized .cm-qualifier { color: #b58900; }
72 | .cm-s-solarized .cm-builtin { color: #d33682; }
73 | .cm-s-solarized .cm-bracket { color: #cb4b16; }
74 | .cm-s-solarized .CodeMirror-matchingbracket { color: #859900; }
75 | .cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; }
76 | .cm-s-solarized .cm-tag { color: #93a1a1; }
77 | .cm-s-solarized .cm-attribute { color: #2aa198; }
78 | .cm-s-solarized .cm-hr {
79 | color: transparent;
80 | border-top: 1px solid #586e75;
81 | display: block;
82 | }
83 | .cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; }
84 | .cm-s-solarized .cm-special { color: #6c71c4; }
85 | .cm-s-solarized .cm-em {
86 | color: #999;
87 | text-decoration: underline;
88 | text-decoration-style: dotted;
89 | }
90 | .cm-s-solarized .cm-error,
91 | .cm-s-solarized .cm-invalidchar {
92 | color: #586e75;
93 | border-bottom: 1px dotted #dc322f;
94 | }
95 |
96 | .cm-s-solarized.cm-s-dark div.CodeMirror-selected { background: #073642; }
97 | .cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); }
98 | .cm-s-solarized.cm-s-dark .CodeMirror-line::-moz-selection, .cm-s-dark .CodeMirror-line > span::-moz-selection, .cm-s-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(7, 54, 66, 0.99); }
99 |
100 | .cm-s-solarized.cm-s-light div.CodeMirror-selected { background: #eee8d5; }
101 | .cm-s-solarized.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: #eee8d5; }
102 | .cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-ligh .CodeMirror-line > span::-moz-selection, .cm-s-ligh .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; }
103 |
104 | /* Editor styling */
105 |
106 |
107 |
108 | /* Little shadow on the view-port of the buffer view */
109 | .cm-s-solarized.CodeMirror {
110 | -moz-box-shadow: inset 7px 0 12px -6px #000;
111 | -webkit-box-shadow: inset 7px 0 12px -6px #000;
112 | box-shadow: inset 7px 0 12px -6px #000;
113 | }
114 |
115 | /* Remove gutter border */
116 | .cm-s-solarized .CodeMirror-gutters {
117 | border-right: 0;
118 | }
119 |
120 | /* Gutter colors and line number styling based of color scheme (dark / light) */
121 |
122 | /* Dark */
123 | .cm-s-solarized.cm-s-dark .CodeMirror-gutters {
124 | background-color: #073642;
125 | }
126 |
127 | .cm-s-solarized.cm-s-dark .CodeMirror-linenumber {
128 | color: #586e75;
129 | text-shadow: #021014 0 -1px;
130 | }
131 |
132 | /* Light */
133 | .cm-s-solarized.cm-s-light .CodeMirror-gutters {
134 | background-color: #eee8d5;
135 | }
136 |
137 | .cm-s-solarized.cm-s-light .CodeMirror-linenumber {
138 | color: #839496;
139 | }
140 |
141 | /* Common */
142 | .cm-s-solarized .CodeMirror-linenumber {
143 | padding: 0 5px;
144 | }
145 | .cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; }
146 | .cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; }
147 | .cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; }
148 |
149 | .cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text {
150 | color: #586e75;
151 | }
152 |
153 | /* Cursor */
154 | .cm-s-solarized .CodeMirror-cursor { border-left: 1px solid #819090; }
155 |
156 | /* Fat cursor */
157 | .cm-s-solarized.cm-s-light.cm-fat-cursor .CodeMirror-cursor { background: #77ee77; }
158 | .cm-s-solarized.cm-s-light .cm-animate-fat-cursor { background-color: #77ee77; }
159 | .cm-s-solarized.cm-s-dark.cm-fat-cursor .CodeMirror-cursor { background: #586e75; }
160 | .cm-s-solarized.cm-s-dark .cm-animate-fat-cursor { background-color: #586e75; }
161 |
162 | /* Active line */
163 | .cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {
164 | background: rgba(255, 255, 255, 0.06);
165 | }
166 | .cm-s-solarized.cm-s-light .CodeMirror-activeline-background {
167 | background: rgba(0, 0, 0, 0.06);
168 | }
169 |
--------------------------------------------------------------------------------
/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/storage/.keep
--------------------------------------------------------------------------------
/test/application_system_test_case.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
5 | end
6 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/test/controllers/.keep
--------------------------------------------------------------------------------
/test/controllers/ast_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class AstControllerTest < ActionDispatch::IntegrationTest
4 | test "should get index" do
5 | get ast_index_url
6 | assert_response :success
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/test/controllers/gist_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class GistControllerTest < ActionDispatch::IntegrationTest
4 | test "should get show" do
5 | get gist_show_url
6 | assert_response :success
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/test/controllers/sessions_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsControllerTest < ActionDispatch::IntegrationTest
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/controllers/welcome_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class WelcomeControllerTest < ActionDispatch::IntegrationTest
4 | test "should get index" do
5 | get welcome_index_url
6 | assert_response :success
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/fixtures/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/test/fixtures/files/.keep
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/test/helpers/.keep
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/test/integration/.keep
--------------------------------------------------------------------------------
/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/test/mailers/.keep
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/test/models/.keep
--------------------------------------------------------------------------------
/test/system/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/test/system/.keep
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require_relative '../config/environment'
3 | require 'rails/test_help'
4 |
5 | class ActiveSupport::TestCase
6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
7 | fixtures :all
8 |
9 | # Add more helper methods to be used by all tests here...
10 | end
11 |
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/tmp/.keep
--------------------------------------------------------------------------------
/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rajasegar/ruby-ast-explorer/e5c3a402bd1195248d0d2d7b97856c1fd286e0d3/vendor/.keep
--------------------------------------------------------------------------------