├── spec ├── fixtures │ ├── db │ │ └── schema.rb │ └── app │ │ ├── models │ │ └── user.rb │ │ ├── helpers │ │ └── users_helper.rb │ │ ├── controllers │ │ ├── user_controller.rb │ │ ├── sessions_controller.rb │ │ ├── users_controller.rb │ │ └── admin │ │ │ └── users_controller.rb │ │ └── views │ │ └── users │ │ └── index.html.erb ├── atom-rails-spec.coffee ├── file-spec.coffee ├── related-spec.coffee └── model-spec.coffee ├── lib ├── file.coffee ├── atom-rails.coffee ├── related.coffee └── model.coffee ├── stylesheets └── atom-rails.less ├── menus └── atom-rails.cson ├── package.json ├── keymaps └── atom-rails.cson ├── README.md └── LICENSE.md /spec/fixtures/db/schema.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/app/models/user.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/atom-rails-spec.coffee: -------------------------------------------------------------------------------- 1 | #TODO 2 | -------------------------------------------------------------------------------- /spec/fixtures/app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/app/controllers/user_controller.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/app/controllers/admin/users_controller.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/file.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | class File 3 | 4 | openFile: (file) -> 5 | if file? 6 | atom.workspaceView.open(file) 7 | else 8 | atom.beep() 9 | -------------------------------------------------------------------------------- /stylesheets/atom-rails.less: -------------------------------------------------------------------------------- 1 | // The ui-variables file is provided by base themes provided by Atom. 2 | // 3 | // See https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less 4 | // for a full listing of what's available. 5 | @import "ui-variables"; 6 | 7 | .atom-rails { 8 | } 9 | -------------------------------------------------------------------------------- /menus/atom-rails.cson: -------------------------------------------------------------------------------- 1 | # See https://atom.io/docs/latest/creating-a-package#menus for more details 2 | 'menu': [ 3 | { 4 | 'label': 'Packages' 5 | 'submenu': [ 6 | 'label': 'atom-rails' 7 | 'submenu': [ 8 | { 'label': 'Switch To Model', 'command': 'atom-rails:switch-to-model' } 9 | { 'label': 'Related', 'command': 'atom-rails:related' } 10 | ] 11 | ] 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atom-rails", 3 | "main": "./lib/atom-rails", 4 | "version": "0.4.0", 5 | "description": "Commands for Ruby on Rails development", 6 | "author": "Tom Kadwill", 7 | "activationEvents": [ 8 | "atom-rails:switch-to-model", 9 | "atom-rails:related" 10 | ], 11 | "repository": "https://github.com/tomkadwill/atom-rails", 12 | "license": "MIT", 13 | "engines": { 14 | "atom": ">0.50.0" 15 | }, 16 | "dependencies": {} 17 | } 18 | -------------------------------------------------------------------------------- /keymaps/atom-rails.cson: -------------------------------------------------------------------------------- 1 | # Keybindings require three things to be fully defined: A selector that is 2 | # matched against the focused element, the keystroke and the command to 3 | # execute. 4 | # 5 | # Below is a basic keybinding which registers on all platforms by applying to 6 | # the root workspace element. 7 | 8 | # For more detailed documentation see 9 | # https://atom.io/docs/latest/advanced/keymaps 10 | '.atom_text_editor': 11 | 'ctrl-alt-m': 'atom-rails:switch-to-model' 12 | 'ctrl-alt-r': 'atom-rails:related' 13 | -------------------------------------------------------------------------------- /spec/file-spec.coffee: -------------------------------------------------------------------------------- 1 | File = require '../lib/file' 2 | {WorkspaceView} = require 'atom' 3 | 4 | describe 'File', -> 5 | describe 'openFile', -> 6 | file = new File() 7 | 8 | it 'opens file when file exists', -> 9 | # This is a bit of a hack 10 | atom.workspaceView = new WorkspaceView 11 | spyOn(atom.workspaceView, 'open').andReturn 'opened' 12 | expect(file.openFile(true)).toEqual 'opened' 13 | 14 | it 'beeps when file does not exist', -> 15 | # This is a bit of a hack 16 | spyOn(atom, 'beep').andReturn 'beep' 17 | expect(file.openFile()).toEqual 'beep' 18 | -------------------------------------------------------------------------------- /lib/atom-rails.coffee: -------------------------------------------------------------------------------- 1 | Model = require './model' 2 | File = require './file' 3 | Related = require './related' 4 | 5 | module.exports = 6 | atomRailsView: null 7 | 8 | activate: (state) -> 9 | atom.workspaceView.command "atom-rails:switch-to-model", => @switchToModel() 10 | atom.workspaceView.command "atom-rails:related", => @related() 11 | 12 | switchToModel: -> 13 | currentFile = atom.workspace.getActiveEditor().getPath() 14 | filePath = new Model(currentFile).path() 15 | new File().openFile(filePath) 16 | 17 | related: -> 18 | currentFile = atom.workspace.getActiveEditor().getPath() 19 | filePath = new Related(currentFile).path() 20 | new File().openFile(filePath) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | atom-rails 2 | ========== 3 | 4 | Commands for Ruby on Rails development. Porting the best features of [tpope's](https://twitter.com/tpope) awesome [vim-rails](https://github.com/tpope/vim-rails) to Atom. 5 | 6 | ## Installing 7 | Use the Atom package manager, which can be found in the Settings view or run `apm install atom-rails` from the command line. 8 | 9 | ## Usage 10 | Navigate between files using the commands below. 11 | 12 | ### Commands 13 | 14 | * `ctrl-alt-m` - Switch to associated model 15 | * controller -> model 16 | * view -> model 17 | * `ctrl-alt-r` - Switch to related file 18 | * model -> db/schema 19 | * controller -> helper 20 | * view -> controller 21 | 22 | ## TODO 23 | 24 | A lot :) 25 | -------------------------------------------------------------------------------- /lib/related.coffee: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | Path = require 'path' 3 | 4 | module.exports = 5 | class Related 6 | constructor: (@currentFile) -> 7 | 8 | path: -> 9 | switch 10 | when @currentFile.match /models\// 11 | path = Path.join atom.project.getPath(), 'db/schema.rb' 12 | return path if fs.existsSync path 13 | when @currentFile.match /controllers\// 14 | path = @currentFile.replace /controller/g, 'helper' 15 | return path if fs.existsSync path 16 | when @currentFile.match /views\// 17 | file = @currentFile.replace(/^.*[\\\/]/, '') 18 | path = @currentFile.replace /views/g, 'controllers' 19 | path = path.replace ('/' + file), '_controller.rb' 20 | return path if fs.existsSync path 21 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lib/model.coffee: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | Path = require 'path' 3 | 4 | module.exports = 5 | class Model 6 | constructor: (@currentFile) -> 7 | 8 | path: -> 9 | if @currentFile.match /_controller\.rb$/ 10 | @getModelForController @currentFile 11 | else if @currentFile.match /views\// 12 | @getModelForView @currentFile 13 | 14 | getModelForController: (currentFile) -> 15 | if currentFile.indexOf("s_controller") != -1 16 | currentFile = currentFile.replace /s_controller\.rb$/, '.rb' 17 | 18 | path = @replaceControllerPath currentFile, /s_controller\.rb$/ 19 | if fs.existsSync path 20 | return path 21 | else 22 | file = currentFile.replace(/^.*[\\\/]/, '') 23 | start = currentFile.indexOf("controllers") 24 | end = currentFile.indexOf(file) 25 | pathToReplace = currentFile.substr(start, end) 26 | path = currentFile.replace pathToReplace, 'models/' + file 27 | return path if fs.existsSync path 28 | else 29 | path = @replaceControllerPath currentFile, /_controller\.rb$/ 30 | return path if fs.existsSync path 31 | 32 | getModelForView: (currentFile) -> 33 | file = currentFile.replace /^.*[\\\/]/, '' 34 | path = currentFile.replace /views\//, 'models/' 35 | path = path.replace '/' + file, '.rb' 36 | path = @singularise path 37 | return path if fs.existsSync path 38 | 39 | singularise: (pluralPath) -> 40 | pluralPath.replace /s\.rb$/, '.rb' 41 | 42 | replaceControllerPath: (currentFile, matcher) -> 43 | currentFile = currentFile.replace matcher, '.rb' 44 | currentFile.replace 'controllers', 'models' 45 | -------------------------------------------------------------------------------- /spec/related-spec.coffee: -------------------------------------------------------------------------------- 1 | Path = require 'path' 2 | Related = require '../lib/related' 3 | 4 | describe 'Related', -> 5 | rootPath = Path.join __dirname, 'fixtures' 6 | 7 | describe 'path', -> 8 | userModel = Path.join rootPath, 'app/models/user.rb' 9 | usersController = Path.join rootPath, 'app/controllers/users_controller.rb' 10 | usersView = Path.join rootPath, 'app/views/users/index.html.erb' 11 | usersHelper = Path.join rootPath, 'app/helpers/users_helper.rb' 12 | schema = Path.join rootPath, 'db/schema.rb' 13 | related = new Related(userModel) 14 | 15 | ## models 16 | it 'returns schema for a model', -> 17 | expect(related.path()).toBe schema 18 | 19 | it 'does not return schema for a controller', -> 20 | related = new Related(usersController) 21 | expect(related.path()).not.toBe schema 22 | 23 | it 'does not return schema for a view', -> 24 | related = new Related(usersView) 25 | expect(related.path()).not.toBe schema 26 | 27 | ## controllers 28 | it 'returns associated helper file for a controller', -> 29 | related = new Related(usersController) 30 | expect(related.path()).toBe usersHelper 31 | 32 | it 'returns nothing if associated helper file for a controller does not exist', -> 33 | sessionsController = Path.join rootPath, 'app/controllers/sessions_controller.rb' 34 | related = new Related(sessionsController) 35 | expect(related.path()).toBeUndefined() 36 | 37 | it 'does not return associated helper for model', -> 38 | related = new Related(userModel) 39 | expect(related.path()).not.toBe usersHelper 40 | 41 | it 'does not return schema for view', -> 42 | related = new Related(usersView) 43 | expect(related.path()).not.toBe usersHelper 44 | 45 | ## views 46 | it 'returns associated controller file for a view', -> 47 | related = new Related(usersView) 48 | expect(related.path()).toBe usersController 49 | -------------------------------------------------------------------------------- /spec/model-spec.coffee: -------------------------------------------------------------------------------- 1 | Path = require 'path' 2 | Model = require '../lib/model' 3 | 4 | describe 'Model', -> 5 | rootPath = Path.join __dirname, 'fixtures' 6 | 7 | describe 'path', -> 8 | usersController = Path.join rootPath, 'app/controllers/users_controller.rb' 9 | usersView = Path.join rootPath, 'app/views/users/index.html.erb' 10 | userModel = Path.join rootPath, 'app/models/user.rb' 11 | model = new Model(usersController) 12 | 13 | ## controllers 14 | it 'returns model for controller', -> 15 | expect(model.path(usersController)).toBe userModel 16 | 17 | it 'returns model when controller is in different directory path', -> 18 | adminUsersController = Path.join rootPath, 'app/controllers/admin/users_controller.rb' 19 | expect(model.path(adminUsersController)).toBe userModel 20 | 21 | it 'returns model when controller does not end is an "s"', -> 22 | adminUsersController = Path.join rootPath, 'app/controllers/user_controller.rb' 23 | expect(model.path(adminUsersController)).toBe userModel 24 | 25 | it 'does not return model file if model file does not exist', -> 26 | sessionsController = Path.join rootPath, 'app/controllers/sessions_controller.rb' 27 | model = new Model(sessionsController) 28 | expect(model.path(sessionsController)).toBeUndefined() 29 | 30 | ## views 31 | it 'returns model for view', -> 32 | model = new Model(usersView) 33 | expect(model.path(usersView)).toBe userModel 34 | 35 | describe 'singularise', -> 36 | pluralPath = Path.join rootPath, 'app/models/users.rb' 37 | singularPath = Path.join rootPath, 'app/models/user.rb' 38 | usersView = Path.join rootPath, 'app/views/users/index.html.erb' 39 | model = new Model(usersView) 40 | 41 | it 'converts plural file name to singular', -> 42 | expect(model.singularise(pluralPath)).toBe singularPath 43 | 44 | describe 'replaceControllerPath', -> 45 | usersController = Path.join rootPath, 'app/controllers/users_controller.rb' 46 | model = new Model(usersController) 47 | userModel = Path.join rootPath, 'app/models/user.rb' 48 | 49 | it 'replaces "s_controller" with ".rb"', -> 50 | expect(model.replaceControllerPath(usersController, /s_controller\.rb$/)).toBe userModel 51 | 52 | it 'replaces "_controller" with ".rb"', -> 53 | userController = Path.join rootPath, 'app/controllers/user_controller.rb' 54 | expect(model.replaceControllerPath(userController, /_controller\.rb$/)).toBe userModel 55 | --------------------------------------------------------------------------------