├── .gitignore ├── Context.sublime-menu ├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── Main.sublime-menu ├── README.markdown ├── Rails.py ├── Rails.sublime-settings ├── __init__.py ├── messages.json ├── messages └── install.txt ├── screenshots ├── context-menu.png └── quick-panel.png └── vendor ├── __init__.py └── inflector ├── __init__.py └── languages ├── __init__.py ├── base.py └── english.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /Context.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { "caption": "-" }, 3 | { "command": "rails_related_files", "args": {"index": 0 }}, 4 | { "command": "rails_related_files", "args": {"index": 1 }}, 5 | { "command": "rails_related_files", "args": {"index": 2 }}, 6 | { "command": "rails_related_files", "args": {"index": 3 }}, 7 | { "command": "rails_related_files", "args": {"index": 4 }}, 8 | { "command": "rails_related_files", "args": {"index": 5 }}, 9 | { "command": "rails_related_files", "args": {"index": 6 }}, 10 | { "command": "rails_related_files", "args": {"index": 7 }}, 11 | { "command": "rails_related_files", "args": {"index": 8 }}, 12 | { "command": "rails_related_files", "args": {"index": 10 }}, 13 | { "command": "rails_related_files", "args": {"index": 11 }}, 14 | { "command": "rails_related_files", "args": {"index": 12 }}, 15 | { "command": "rails_related_files", "args": {"index": 13 }}, 16 | { "command": "rails_related_files", "args": {"index": 14 }}, 17 | { "command": "rails_related_files", "args": {"index": 15 }}, 18 | { "command": "rails_related_files", "args": {"index": 16 }}, 19 | { "command": "rails_related_files", "args": {"index": 17 }}, 20 | { "command": "rails_related_files", "args": {"index": 18 }}, 21 | { "command": "rails_related_files", "args": {"index": 19 }}, 22 | { "command": "rails_related_files", "args": {"index": 20 }}, 23 | { "caption": "-", "id": "end" } 24 | ] -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["super+shift+o"], "command": "rails_related_files", "args": {"index": -1 }} 3 | ] -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["super+shift+o"], "command": "rails_related_files", "args": {"index": -1 }} 3 | ] -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["super+shift+o"], "command": "rails_related_files", "args": {"index": -1 }} 3 | ] -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "Rails Related Files", 16 | "children": 17 | [ 18 | { 19 | "command": "open_file", 20 | "args": {"file": "${packages}/Rails Related Files/README.md"}, 21 | "caption": "README" 22 | }, 23 | { "caption": "-" }, 24 | { 25 | "command": "open_file", 26 | "args": { 27 | "file": "${packages}/Rails Related Files/Default (OSX).sublime-keymap", 28 | "platform": "OSX" 29 | }, 30 | "caption": "Key Bindings – Default" 31 | }, 32 | { 33 | "command": "open_file", 34 | "args": { 35 | "file": "${packages}/Rails Related Files/Default (Linux).sublime-keymap", 36 | "platform": "Linux" 37 | }, 38 | "caption": "Key Bindings – Default" 39 | }, 40 | { 41 | "command": "open_file", 42 | "args": { 43 | "file": "${packages}/Rails Related Files/Default (Windows).sublime-keymap", 44 | "platform": "Windows" 45 | }, 46 | "caption": "Key Bindings – Default" 47 | }, 48 | { 49 | "command": "open_file", 50 | "args": { 51 | "file": "${packages}/User/Default (OSX).sublime-keymap", 52 | "platform": "OSX" 53 | }, 54 | "caption": "Key Bindings – User" 55 | }, 56 | { 57 | "command": "open_file", 58 | "args": { 59 | "file": "${packages}/User/Default (Linux).sublime-keymap", 60 | "platform": "Linux" 61 | }, 62 | "caption": "Key Bindings – User" 63 | }, 64 | { 65 | "command": "open_file", 66 | "args": { 67 | "file": "${packages}/User/Default (Windows).sublime-keymap", 68 | "platform": "Windows" 69 | }, 70 | "caption": "Key Bindings – User" 71 | }, 72 | { "caption": "-" } 73 | ] 74 | } 75 | ] 76 | } 77 | ] 78 | } 79 | ] 80 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Sublime Text 2/3 - Rails Related Files 2 | 3 | Note: I've never written any Python code before! So feel free to implement best practices and make a pull request. 4 | 5 | This plugin allows you to easily navigate your Rails projects by making a few basic assumptions. I wrote this so I didnt have to constantly use the SideBar to lookup files! 6 | 7 | Ok, so lets imagine you "right clicked" on the following file/s (Screenshot 2) or by using the "CMD+Shift+O" shortcut (Screenshot 1) it will search for files: 8 | 9 | `posts_controller.rb` under `app/controllers` 10 | 11 | If it was under the "admin" namespace e.g. `app/controllers/admin/posts_controller.rb` then it will look under `views/admin/posts/**` and vice versa. 12 | 13 | views/posts/** - All files under this folder 14 | models/post** - Models starting with "post" 15 | 16 | `show.html.erb` under `app/views/posts` 17 | 18 | models/post** - Models starting with "post" 19 | views/posts/** - All files in this folder 20 | assets/javascript/post** - Any javascript file starting with "post" 21 | assets/stylesheets/post** - Any stylesheet file starting with "post" 22 | controllers/post** - Any controller file starting with "post" 23 | 24 | `post.rb` model under `app/models` 25 | 26 | models/post** - Models starting with "post" 27 | views/posts/** - All files in this folder 28 | views/**/posts/** - All files in this folder (e.g. admin namespace) 29 | controllers/post** - Any controller starting with "post" 30 | controllers/**/post** - Any controller starting with "post" (e.g. admin namespace) 31 | 32 | If you want to disable the context menu, just edit the `Rails.sublime-settings` file changing "show_context_menu" to false. 33 | 34 | ### Future 35 | 36 | Maybe we can extract the possible partials being used in the current file e.g. `render "post"` or even `render @posts`, we know where to look > app/views/posts/_post 37 | 38 | ### Screenshots 39 | 40 | Here I've pressed the shortcut key when looking at the "page.rb" file under models. 41 | 42 | Quick Panel 43 | 44 | ![Quick Panel](https://github.com/luqman/SublimeText2RailsRelatedFiles/raw/master/screenshots/quick-panel.png) 45 | 46 | Context Menu 47 | 48 | ![Context Menu](https://github.com/luqman/SublimeText2RailsRelatedFiles/raw/master/screenshots/context-menu.png) 49 | 50 | ### Contributors 51 | 52 | - https://github.com/fredwu - Fred Wu - added support for test/spec files 53 | - https://github.com/bratsche - Cody Russell - bug fix 54 | - https://github.com/deiga - Timo Sand - Sublime Menu Entries, Support for helper Files 55 | - https://github.com/nahaylo - Vitaliy Nahaylo - ST3 compatibility fix 56 | 57 | ### Credits 58 | 59 | - Python version of Rails Inflector https://bitbucket.org/ixmatus/inflector 60 | - Tiny copy/paste from https://github.com/kemayo/sublime-text-2-git 61 | -------------------------------------------------------------------------------- /Rails.py: -------------------------------------------------------------------------------- 1 | import sublime, sublime_plugin, os, glob, re 2 | 3 | try: 4 | from .vendor.inflector import * 5 | except ValueError: 6 | from vendor.inflector import * 7 | 8 | # @author Luqman Amjad http://luqmanamjad.com 9 | 10 | # Taken from Git Plugin (Changed to detected Rails root) 11 | def rails_root(directory): 12 | while directory: 13 | if os.path.exists(os.path.join(directory, 'Rakefile')): 14 | return directory 15 | parent = os.path.realpath(os.path.join(directory, os.path.pardir)) 16 | if parent == directory: 17 | # /.. == / 18 | return False 19 | directory = parent 20 | return False 21 | 22 | class RailsRelatedFilesHelper: 23 | 24 | @staticmethod 25 | def get_directory_listing_without_folders(path): 26 | 27 | files = [] 28 | result = glob.glob(path) 29 | 30 | for _file in result: 31 | 32 | if not os.path.isdir(_file): 33 | files.append(_file) 34 | 35 | return files 36 | 37 | @staticmethod 38 | def for_controllers(app_folder, working_directory, base_file_name): 39 | 40 | controller = base_file_name.replace('_controller', '') 41 | model = Inflector(English).singularize(controller).lower() 42 | 43 | namespace_directory = RailsRelatedFilesHelper.get_namespace_directory(working_directory) 44 | working_directory_base = os.path.basename(working_directory) 45 | 46 | if namespace_directory: 47 | 48 | controller = os.path.join(working_directory_base, controller) 49 | 50 | walkers = [ 51 | 'app/models/' + model + '*', 52 | 'app/models/**/' + model + '*', 53 | 'app/helpers/' + controller + '**', 54 | 'app/helpers/**/' + controller + '**', 55 | 'app/views/' + controller + '/**', 56 | 'app/views/**/' + controller + '/**', 57 | 'test/' + controller + '**', 58 | 'test/**/' + controller + '**', 59 | 'spec/' + controller + '**', 60 | 'spec/**/' + controller + '**' 61 | ] 62 | 63 | return RailsRelatedFilesHelper.get_files_while_walking(app_folder, walkers) 64 | 65 | @staticmethod 66 | def for_helpers(app_folder, working_directory, base_file_name): 67 | 68 | helper = base_file_name.replace('_helper', '') 69 | model = Inflector(English).singularize(helper).lower() 70 | 71 | namespace_directory = RailsRelatedFilesHelper.get_namespace_directory(working_directory) 72 | working_directory_base = os.path.basename(working_directory) 73 | 74 | if namespace_directory: 75 | 76 | helper = os.path.join(working_directory_base, helper) 77 | 78 | walkers = [ 79 | 'app/models/' + model + '*', 80 | 'app/models/**/' + model + '*', 81 | 'app/controllers/' + helper + '**', 82 | 'app/controllers/**/' + helper + '**', 83 | 'app/views/' + helper + '/**', 84 | 'app/views/**/' + helper + '/**', 85 | 'test/' + helper + '**', 86 | 'test/**/' + helper + '**', 87 | 'spec/' + helper + '**', 88 | 'spec/**/' + helper + '**' 89 | ] 90 | 91 | return RailsRelatedFilesHelper.get_files_while_walking(app_folder, walkers) 92 | 93 | @staticmethod 94 | def for_views(app_folder, working_directory): 95 | 96 | working_directory_base = os.path.basename(working_directory) #if app/views/posts it should return "posts" 97 | model = Inflector(English).singularize(os.path.basename(working_directory_base)).lower() # should return "post" 98 | namespace_directory = RailsRelatedFilesHelper.get_namespace_directory(working_directory) #should return none 99 | controller = model 100 | 101 | if namespace_directory: 102 | working_directory_base = namespace_directory 103 | 104 | controller = os.path.join(os.path.split(working_directory_base)[0], controller) 105 | 106 | walkers = [ 107 | 'app/models/' + model + '**', 108 | 'app/models/**/' + model + '**', 109 | 'app/views/' + working_directory_base + '/**', 110 | 'app/helpers/' + controller + '**', 111 | 'app/helpers/**/' + controller + '**', 112 | 'app/assets/javascripts/' + model + '**', 113 | 'app/assets/stylesheets/' + model + '**', 114 | 'app/controllers/' + controller + '**', 115 | 'app/controllers/**/' + controller + '**', 116 | 'test/' + controller + '**', 117 | 'test/**/' + controller + '**', 118 | 'spec/' + controller + '**', 119 | 'spec/**/' + controller + '**' 120 | ] 121 | 122 | return RailsRelatedFilesHelper.get_files_while_walking(app_folder, walkers) 123 | 124 | @staticmethod 125 | def for_models(app_folder, working_directory, file_name_base_no_ext): 126 | 127 | model = Inflector(English).singularize(file_name_base_no_ext).lower() 128 | controller = Inflector(English).pluralize(file_name_base_no_ext).lower() 129 | 130 | walkers = [ 131 | 'app/models/' + model + '**', 132 | 'app/models/**/' + model + '**', 133 | 'app/helpers/' + controller + '**', 134 | 'app/helpers/**/' + controller + '**', 135 | 'app/views/' + controller + '/**', 136 | 'app/views/**/' + controller + '/**', 137 | 'app/controllers/' + controller + '**', 138 | 'app/controllers/**/' + controller + '**', 139 | 'test/' + model + '**', 140 | 'test/**/' + model + '**', 141 | 'spec/' + model + '**', 142 | 'spec/**/' + model + '**' 143 | ] 144 | 145 | return RailsRelatedFilesHelper.get_files_while_walking(app_folder, walkers) 146 | 147 | @staticmethod 148 | def for_tests(app_folder, working_directory, base_file_name): 149 | 150 | if '_controller' in base_file_name: 151 | controller = base_file_name.replace('_controller', '').replace('_spec', '').replace('_test', '').replace('test_', '') 152 | model = Inflector(English).singularize(controller).lower() 153 | else: 154 | model = base_file_name.replace('_spec', '').replace('test_', '') 155 | controller = Inflector(English).pluralize(model).lower() 156 | 157 | walkers = [ 158 | 'app/controllers/' + controller + '**', 159 | 'app/controllers/**/' + controller + '**', 160 | 'app/models/' + model + '**', 161 | 'app/models/**/' + model + '**', 162 | 'app/helpers/' + controller + '**', 163 | 'app/helpers/**/' + controller + '**', 164 | 'app/views/' + controller + '/**', 165 | 'app/views/**/' + controller + '/**' 166 | ] 167 | 168 | return RailsRelatedFilesHelper.get_files_while_walking(app_folder, walkers) 169 | 170 | 171 | @staticmethod 172 | def get_app_sub_directory(filename): 173 | 174 | regex = re.compile('(app\/views|app\/controllers|app\/helpers|app\/models|app\/assets|test|spec)') 175 | match = regex.findall(filename) 176 | 177 | if match: 178 | 179 | return match[0] 180 | 181 | else: 182 | 183 | return 184 | 185 | @staticmethod 186 | def get_namespace_directory(directory): 187 | 188 | regex = re.compile('(\/app\/views|controllers|helpers|test|spec)\/(.*)') #amazing regex skills... 189 | match = regex.findall(directory) 190 | 191 | if match: 192 | 193 | return match[0][1] 194 | 195 | else: 196 | 197 | return 198 | 199 | @staticmethod 200 | def get_files_while_walking(app_folder, walkers): 201 | 202 | files = [] 203 | 204 | for walker in walkers: 205 | 206 | files += ( 207 | RailsRelatedFilesHelper().get_directory_listing_without_folders(app_folder + '/' + walker) 208 | ) 209 | 210 | files_without_full_path = [] 211 | for _file in files: 212 | 213 | files_without_full_path += [_file.replace(app_folder + '/', '')] 214 | 215 | return files_without_full_path 216 | 217 | class RailsRelatedFilesCommand(sublime_plugin.TextCommand): 218 | 219 | APP_FOLDERS = ['app/controllers', 'app/helpers', 'app/models', 'app/views', 'test', 'spec'] #assets 220 | 221 | def run(self, edit, index): 222 | 223 | if index >= 0: 224 | 225 | self.open_file(index) 226 | 227 | else: 228 | 229 | try: 230 | 231 | self.build_files() 232 | sublime.active_window().show_quick_panel(self.files, self.open_file) 233 | 234 | except: 235 | 236 | return False 237 | 238 | def is_visible(self, index): 239 | 240 | #return True 241 | 242 | try: 243 | 244 | return self.files[index] and self.show_context_menu 245 | 246 | except: # This should catch all exceptions and return false 247 | 248 | return False 249 | 250 | def open_file(self, index): 251 | 252 | if index >= 0: 253 | 254 | sublime.active_window().open_file(os.path.join(self.rails_root_directory, self.files[index])) 255 | 256 | def build_files(self): 257 | 258 | self.files = [] 259 | self.rails_root_directory = rails_root(self.get_working_dir()) 260 | 261 | if self.rails_root_directory: 262 | 263 | self.show_context_menu = sublime.load_settings("Rails.sublime-settings").get('show_context_menu') 264 | 265 | current_file_name = self._active_file_name() 266 | working_directory = self.get_working_dir().replace("\\",'/') 267 | working_directory_base = os.path.basename(working_directory) 268 | 269 | file_name_base = os.path.basename(current_file_name) 270 | file_name_base_no_ext = os.path.splitext(file_name_base)[0] 271 | 272 | app_sub_directory = RailsRelatedFilesHelper.get_app_sub_directory(working_directory) 273 | 274 | if app_sub_directory in self.APP_FOLDERS: 275 | 276 | func, args = { 277 | 'app/controllers': (RailsRelatedFilesHelper.for_controllers, (self.rails_root_directory, working_directory, file_name_base_no_ext,)), 278 | 'app/helpers' : (RailsRelatedFilesHelper.for_helpers, (self.rails_root_directory, working_directory, file_name_base_no_ext,)), 279 | 'app/views' : (RailsRelatedFilesHelper.for_views, (self.rails_root_directory, working_directory,)), 280 | 'app/models' : (RailsRelatedFilesHelper.for_models, (self.rails_root_directory, working_directory, file_name_base_no_ext,)), 281 | 'test' : (RailsRelatedFilesHelper.for_tests, (self.rails_root_directory, working_directory, file_name_base_no_ext,)), 282 | 'spec' : (RailsRelatedFilesHelper.for_tests, (self.rails_root_directory, working_directory, file_name_base_no_ext,)) 283 | }.get(app_sub_directory) 284 | 285 | self.files = func(*args) 286 | 287 | if not self.files: 288 | self.files = ['Rails Related Files: Nothing found...'] 289 | 290 | 291 | def description(self, index): 292 | self.build_files() 293 | try: 294 | return self.files[index] 295 | except IndexError as e: 296 | return 297 | 298 | # Taken from Git Plugin (Changed .active_view() to .view) 299 | def _active_file_name(self): 300 | view = self.view; 301 | if view and view.file_name() and len(view.file_name()) > 0: 302 | return view.file_name() 303 | 304 | # Taken from Git Plugin 305 | def get_working_dir(self): 306 | file_name = self._active_file_name() 307 | if file_name: 308 | return os.path.dirname(file_name) 309 | else: 310 | return self.window.folders()[0] 311 | 312 | -------------------------------------------------------------------------------- /Rails.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "show_context_menu": true 3 | } -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luqman/SublimeText2RailsRelatedFiles/d7fb3a4bf421276213e109b6a2648a21014b5664/__init__.py -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.txt" 3 | } 4 | -------------------------------------------------------------------------------- /messages/install.txt: -------------------------------------------------------------------------------- 1 | --------------------------------------- 2 | Rails Related Files 3 | --------------------------------------- 4 | 5 | Thank You for installing Rails Related Files. 6 | 7 | cmd+shiftq(Mac)/super+shift+o(Linux/Windows) to bring up the Quick Panel Option. 8 | 9 | Simply right-click to bring up the Context Menu Option. 10 | -------------------------------------------------------------------------------- /screenshots/context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luqman/SublimeText2RailsRelatedFiles/d7fb3a4bf421276213e109b6a2648a21014b5664/screenshots/context-menu.png -------------------------------------------------------------------------------- /screenshots/quick-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luqman/SublimeText2RailsRelatedFiles/d7fb3a4bf421276213e109b6a2648a21014b5664/screenshots/quick-panel.png -------------------------------------------------------------------------------- /vendor/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luqman/SublimeText2RailsRelatedFiles/d7fb3a4bf421276213e109b6a2648a21014b5664/vendor/__init__.py -------------------------------------------------------------------------------- /vendor/inflector/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006 Bermi Ferrer Martinez 2 | # 3 | # bermi a-t bermilabs - com 4 | # See the end of this file for the free software, open source license (BSD-style). 5 | 6 | try: 7 | from .languages.english import English 8 | except ValueError: 9 | from languages.english import English 10 | 11 | class Inflector(object): 12 | """ 13 | Inflector for pluralizing and singularizing nouns. 14 | 15 | It provides methods for helping on creating programs 16 | based on naming conventions like on Ruby on Rails. 17 | """ 18 | 19 | def __init__( self, Inflector = English ) : 20 | assert callable(Inflector), "Inflector should be a callable obj" 21 | self.Inflector = Inflector; 22 | 23 | def pluralize(self, word) : 24 | '''Pluralizes nouns.''' 25 | return self.Inflector.pluralize(self, word) 26 | 27 | def singularize(self, word) : 28 | '''Singularizes nouns.''' 29 | return self.Inflector.singularize(self, word) 30 | 31 | def conditionalPlural(self, numer_of_records, word) : 32 | '''Returns the plural form of a word if first parameter is greater than 1''' 33 | return self.Inflector.conditionalPlural(numer_of_records, word) 34 | 35 | def titleize(self, word, uppercase = '') : 36 | '''Converts an underscored or CamelCase word into a sentence. 37 | The titleize function converts text like "WelcomePage", 38 | "welcome_page" or "welcome page" to this "Welcome Page". 39 | If the "uppercase" parameter is set to 'first' it will only 40 | capitalize the first character of the title.''' 41 | return self.Inflector.titleize(word, uppercase) 42 | 43 | def camelize(self, word): 44 | ''' Returns given word as CamelCased 45 | Converts a word like "send_email" to "SendEmail". It 46 | will remove non alphanumeric character from the word, so 47 | "who's online" will be converted to "WhoSOnline"''' 48 | return self.Inflector.camelize(word) 49 | 50 | def underscore(self, word) : 51 | ''' Converts a word "into_it_s_underscored_version" 52 | Convert any "CamelCased" or "ordinary Word" into an 53 | "underscored_word". 54 | This can be really useful for creating friendly URLs.''' 55 | return self.Inflector.underscore(word) 56 | 57 | def humanize(self, word, uppercase = '') : 58 | '''Returns a human-readable string from word 59 | Returns a human-readable string from word, by replacing 60 | underscores with a space, and by upper-casing the initial 61 | character by default. 62 | If you need to uppercase all the words you just have to 63 | pass 'all' as a second parameter.''' 64 | return self.Inflector.humanize(word, uppercase) 65 | 66 | 67 | def variablize(self, word) : 68 | '''Same as camelize but first char is lowercased 69 | Converts a word like "send_email" to "sendEmail". It 70 | will remove non alphanumeric character from the word, so 71 | "who's online" will be converted to "whoSOnline"''' 72 | return self.Inflector.variablize(word) 73 | 74 | def tableize(self, class_name) : 75 | ''' Converts a class name to its table name according to rails 76 | naming conventions. Example. Converts "Person" to "people" ''' 77 | return self.Inflector.tableize(class_name) 78 | 79 | def classify(self, table_name) : 80 | '''Converts a table name to its class name according to rails 81 | naming conventions. Example: Converts "people" to "Person" ''' 82 | return self.Inflector.classify(table_name) 83 | 84 | def ordinalize(self, number) : 85 | '''Converts number to its ordinal form. 86 | This method converts 13 to 13th, 2 to 2nd ...''' 87 | return self.Inflector.ordinalize(number) 88 | 89 | 90 | def unaccent(self, text) : 91 | '''Transforms a string to its unaccented version. 92 | This might be useful for generating "friendly" URLs''' 93 | return self.Inflector.unaccent(text) 94 | 95 | def urlize(self, text) : 96 | '''Transform a string its unaccented and underscored 97 | version ready to be inserted in friendly URLs''' 98 | return self.Inflector.urlize(text) 99 | 100 | 101 | def demodulize(self, module_name) : 102 | return self.Inflector.demodulize(module_name) 103 | 104 | def modulize(self, module_description) : 105 | return self.Inflector.modulize(module_description) 106 | 107 | def foreignKey(self, class_name, separate_class_name_and_id_with_underscore = 1) : 108 | ''' Returns class_name in underscored form, with "_id" tacked on at the end. 109 | This is for use in dealing with the database.''' 110 | return self.Inflector.foreignKey(class_name, separate_class_name_and_id_with_underscore) 111 | 112 | 113 | 114 | 115 | # Copyright (c) 2006 Bermi Ferrer Martinez 116 | # Permission is hereby granted, free of charge, to any person obtaining a copy 117 | # of this software to deal in this software without restriction, including 118 | # without limitation the rights to use, copy, modify, merge, publish, 119 | # distribute, sublicense, and/or sell copies of this software, and to permit 120 | # persons to whom this software is furnished to do so, subject to the following 121 | # condition: 122 | # 123 | # THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 124 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 125 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 126 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 127 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 128 | # OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN 129 | # THIS SOFTWARE. 130 | -------------------------------------------------------------------------------- /vendor/inflector/languages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luqman/SublimeText2RailsRelatedFiles/d7fb3a4bf421276213e109b6a2648a21014b5664/vendor/inflector/languages/__init__.py -------------------------------------------------------------------------------- /vendor/inflector/languages/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2006 Bermi Ferrer Martinez 4 | # bermi a-t bermilabs - com 5 | # See the end of this file for the free software, open source license (BSD-style). 6 | 7 | import re 8 | 9 | class Base(object): 10 | '''Locale inflectors must inherit from this base class inorder to provide 11 | the basic Inflector functionality''' 12 | 13 | def conditionalPlural(self, numer_of_records, word) : 14 | '''Returns the plural form of a word if first parameter is greater than 1''' 15 | 16 | if numer_of_records > 1 : 17 | return self.pluralize(word) 18 | else : 19 | return word 20 | 21 | 22 | def titleize(self, word, uppercase = '') : 23 | '''Converts an underscored or CamelCase word into a English sentence. 24 | The titleize function converts text like "WelcomePage", 25 | "welcome_page" or "welcome page" to this "Welcome Page". 26 | If second parameter is set to 'first' it will only 27 | capitalize the first character of the title.''' 28 | 29 | if(uppercase == 'first'): 30 | return self.humanize(self.underscore(word)).capitalize() 31 | else : 32 | return self.humanize(self.underscore(word)).title() 33 | 34 | 35 | def camelize(self, word): 36 | ''' Returns given word as CamelCased 37 | Converts a word like "send_email" to "SendEmail". It 38 | will remove non alphanumeric character from the word, so 39 | "who's online" will be converted to "WhoSOnline"''' 40 | return ''.join(w[0].upper() + w[1:] for w in re.sub('[^A-Z^a-z^0-9^:]+', ' ', word).split(' ')) 41 | 42 | def underscore(self, word) : 43 | ''' Converts a word "into_it_s_underscored_version" 44 | Convert any "CamelCased" or "ordinary Word" into an 45 | "underscored_word". 46 | This can be really useful for creating friendly URLs.''' 47 | 48 | return re.sub('[^A-Z^a-z^0-9^\/]+','_', \ 49 | re.sub('([a-z\d])([A-Z])','\\1_\\2', \ 50 | re.sub('([A-Z]+)([A-Z][a-z])','\\1_\\2', re.sub('::', '/',word)))).lower() 51 | 52 | 53 | def humanize(self, word, uppercase = '') : 54 | '''Returns a human-readable string from word 55 | Returns a human-readable string from word, by replacing 56 | underscores with a space, and by upper-casing the initial 57 | character by default. 58 | If you need to uppercase all the words you just have to 59 | pass 'all' as a second parameter.''' 60 | 61 | if(uppercase == 'first'): 62 | return re.sub('_id$', '', word).replace('_',' ').capitalize() 63 | else : 64 | return re.sub('_id$', '', word).replace('_',' ').title() 65 | 66 | 67 | def variablize(self, word) : 68 | '''Same as camelize but first char is lowercased 69 | Converts a word like "send_email" to "sendEmail". It 70 | will remove non alphanumeric character from the word, so 71 | "who's online" will be converted to "whoSOnline"''' 72 | word = self.camelize(word) 73 | return word[0].lower()+word[1:] 74 | 75 | def tableize(self, class_name) : 76 | ''' Converts a class name to its table name according to rails 77 | naming conventions. Example. Converts "Person" to "people" ''' 78 | return self.pluralize(self.underscore(class_name)) 79 | 80 | 81 | def classify(self, table_name) : 82 | '''Converts a table name to its class name according to rails 83 | naming conventions. Example: Converts "people" to "Person" ''' 84 | return self.camelize(self.singularize(table_name)) 85 | 86 | 87 | def ordinalize(self, number) : 88 | '''Converts number to its ordinal English form. 89 | This method converts 13 to 13th, 2 to 2nd ...''' 90 | tail = 'th' 91 | if number % 100 == 11 or number % 100 == 12 or number % 100 == 13: 92 | tail = 'th' 93 | elif number % 10 == 1 : 94 | tail = 'st' 95 | elif number % 10 == 2 : 96 | tail = 'nd' 97 | elif number % 10 == 3 : 98 | tail = 'rd' 99 | 100 | return str(number)+tail 101 | 102 | 103 | def unaccent(self, text) : 104 | '''Transforms a string to its unaccented version. 105 | This might be useful for generating "friendly" URLs''' 106 | find = u'\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF' 107 | replace = u'AAAAAAACEEEEIIIIDNOOOOOOUUUUYTsaaaaaaaceeeeiiiienoooooouuuuyty' 108 | return self.string_replace(text, find, replace) 109 | 110 | def string_replace (self, word, find, replace) : 111 | '''This function returns a copy of word, translating 112 | all occurrences of each character in find to the 113 | corresponding character in replace''' 114 | for k in range(0,len(find)) : 115 | word = re.sub(find[k], replace[k], word) 116 | 117 | return word 118 | 119 | def urlize(self, text) : 120 | '''Transform a string its unaccented and underscored 121 | version ready to be inserted in friendly URLs''' 122 | return re.sub('^_|_$','',self.underscore(self.unaccent(text))) 123 | 124 | 125 | def demodulize(self, module_name) : 126 | return self.humanize(self.underscore(re.sub('^.*::','',module_name))) 127 | 128 | def modulize(self, module_description) : 129 | return self.camelize(self.singularize(module_description)) 130 | 131 | def foreignKey(self, class_name, separate_class_name_and_id_with_underscore = 1) : 132 | ''' Returns class_name in underscored form, with "_id" tacked on at the end. 133 | This is for use in dealing with the database.''' 134 | if separate_class_name_and_id_with_underscore : 135 | tail = '_id' 136 | else : 137 | tail = 'id' 138 | return self.underscore(self.demodulize(class_name))+tail; 139 | 140 | 141 | 142 | # Copyright (c) 2006 Bermi Ferrer Martinez 143 | # Permission is hereby granted, free of charge, to any person obtaining a copy 144 | # of this software to deal in this software without restriction, including 145 | # without limitation the rights to use, copy, modify, merge, publish, 146 | # distribute, sublicense, and/or sell copies of this software, and to permit 147 | # persons to whom this software is furnished to do so, subject to the following 148 | # condition: 149 | # 150 | # THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 151 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 152 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 153 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 154 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 155 | # OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN 156 | # THIS SOFTWARE. 157 | -------------------------------------------------------------------------------- /vendor/inflector/languages/english.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2006 Bermi Ferrer Martinez 4 | # bermi a-t bermilabs - com 5 | # 6 | # See the end of this file for the free software, open source license (BSD-style). 7 | 8 | import re 9 | 10 | try: 11 | from .base import Base 12 | except ValueError: 13 | from base import Base 14 | 15 | class English (Base): 16 | """ 17 | Inflector for pluralize and singularize English nouns. 18 | 19 | This is the default Inflector for the Inflector obj 20 | """ 21 | 22 | def pluralize(self, word) : 23 | '''Pluralizes English nouns.''' 24 | 25 | rules = [ 26 | ['(?i)(quiz)$' , '\\1zes'], 27 | ['^(?i)(ox)$' , '\\1en'], 28 | ['(?i)([m|l])ouse$' , '\\1ice'], 29 | ['(?i)(matr|vert|ind)ix|ex$' , '\\1ices'], 30 | ['(?i)(x|ch|ss|sh)$' , '\\1es'], 31 | ['(?i)([^aeiouy]|qu)ies$' , '\\1y'], 32 | ['(?i)([^aeiouy]|qu)y$' , '\\1ies'], 33 | ['(?i)(hive)$' , '\\1s'], 34 | ['(?i)(?:([^f])fe|([lr])f)$' , '\\1\\2ves'], 35 | ['(?i)sis$' , 'ses'], 36 | ['(?i)([ti])um$' , '\\1a'], 37 | ['(?i)(buffal|tomat)o$' , '\\1oes'], 38 | ['(?i)(bu)s$' , '\\1ses'], 39 | ['(?i)(alias|status)' , '\\1es'], 40 | ['(?i)(octop|vir)us$' , '\\1i'], 41 | ['(?i)(ax|test)is$' , '\\1es'], 42 | ['(?i)s$' , 's'], 43 | ['(?i)$' , 's'] 44 | ] 45 | 46 | uncountable_words = ['equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep'] 47 | 48 | irregular_words = { 49 | 'person' : 'people', 50 | 'man' : 'men', 51 | 'child' : 'children', 52 | 'sex' : 'sexes', 53 | 'move' : 'moves' 54 | } 55 | 56 | lower_cased_word = word.lower(); 57 | 58 | for uncountable_word in uncountable_words: 59 | if lower_cased_word[-1*len(uncountable_word):] == uncountable_word : 60 | return word 61 | 62 | for irregular in irregular_words.keys(): 63 | match = re.search('('+irregular+')$',word, re.IGNORECASE) 64 | if match: 65 | return re.sub('(?i)'+irregular+'$', match.expand('\\1')[0]+irregular_words[irregular][1:], word) 66 | 67 | for rule in range(len(rules)): 68 | match = re.search(rules[rule][0], word, re.IGNORECASE) 69 | if match : 70 | groups = match.groups() 71 | for k in range(0,len(groups)) : 72 | if groups[k] == None : 73 | rules[rule][1] = rules[rule][1].replace('\\'+str(k+1), '') 74 | 75 | return re.sub(rules[rule][0], rules[rule][1], word) 76 | 77 | return word 78 | 79 | 80 | def singularize (self, word) : 81 | '''Singularizes English nouns.''' 82 | 83 | rules = [ 84 | ['(?i)(quiz)zes$' , '\\1'], 85 | ['(?i)(matr)ices$' , '\\1ix'], 86 | ['(?i)(vert|ind)ices$' , '\\1ex'], 87 | ['(?i)^(ox)en' , '\\1'], 88 | ['(?i)(alias|status)es$' , '\\1'], 89 | ['(?i)([octop|vir])i$' , '\\1us'], 90 | ['(?i)(cris|ax|test)es$' , '\\1is'], 91 | ['(?i)(shoe)s$' , '\\1'], 92 | ['(?i)(o)es$' , '\\1'], 93 | ['(?i)(bus)es$' , '\\1'], 94 | ['(?i)([m|l])ice$' , '\\1ouse'], 95 | ['(?i)(x|ch|ss|sh)es$' , '\\1'], 96 | ['(?i)(m)ovies$' , '\\1ovie'], 97 | ['(?i)(s)eries$' , '\\1eries'], 98 | ['(?i)([^aeiouy]|qu)ies$' , '\\1y'], 99 | ['(?i)([lr])ves$' , '\\1f'], 100 | ['(?i)(tive)s$' , '\\1'], 101 | ['(?i)(hive)s$' , '\\1'], 102 | ['(?i)([^f])ves$' , '\\1fe'], 103 | ['(?i)(^analy)ses$' , '\\1sis'], 104 | ['(?i)((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$' , '\\1\\2sis'], 105 | ['(?i)([ti])a$' , '\\1um'], 106 | ['(?i)(n)ews$' , '\\1ews'], 107 | ['(?i)s$' , ''], 108 | ]; 109 | 110 | uncountable_words = ['equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep','sms']; 111 | 112 | irregular_words = { 113 | 'people' : 'person', 114 | 'men' : 'man', 115 | 'children' : 'child', 116 | 'sexes' : 'sex', 117 | 'moves' : 'move' 118 | } 119 | 120 | lower_cased_word = word.lower(); 121 | 122 | for uncountable_word in uncountable_words: 123 | if lower_cased_word[-1*len(uncountable_word):] == uncountable_word : 124 | return word 125 | 126 | for irregular in irregular_words.keys(): 127 | match = re.search('('+irregular+')$',word, re.IGNORECASE) 128 | if match: 129 | return re.sub('(?i)'+irregular+'$', match.expand('\\1')[0]+irregular_words[irregular][1:], word) 130 | 131 | 132 | for rule in range(len(rules)): 133 | match = re.search(rules[rule][0], word, re.IGNORECASE) 134 | if match : 135 | groups = match.groups() 136 | for k in range(0,len(groups)) : 137 | if groups[k] == None : 138 | rules[rule][1] = rules[rule][1].replace('\\'+str(k+1), '') 139 | 140 | return re.sub(rules[rule][0], rules[rule][1], word) 141 | 142 | return word 143 | 144 | 145 | 146 | # Copyright (c) 2006 Bermi Ferrer Martinez 147 | # Permission is hereby granted, free of charge, to any person obtaining a copy 148 | # of this software to deal in this software without restriction, including 149 | # without limitation the rights to use, copy, modify, merge, publish, 150 | # distribute, sublicense, and/or sell copies of this software, and to permit 151 | # persons to whom this software is furnished to do so, subject to the following 152 | # condition: 153 | # 154 | # THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 155 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 156 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 157 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 158 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 159 | # OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN 160 | # THIS SOFTWARE. 161 | --------------------------------------------------------------------------------