pax_global_header00006660000000000000000000000064134054724720014522gustar00rootroot0000000000000052 comment=f032dde1ca55aed73025b1d642a39d9aed422ce1 ruby-js-routes-1.4.4/000077500000000000000000000000001340547247200144425ustar00rootroot00000000000000ruby-js-routes-1.4.4/.document000066400000000000000000000000671340547247200162640ustar00rootroot00000000000000lib/**/*.rb bin/* - features/**/*.feature LICENSE.txt ruby-js-routes-1.4.4/.gitignore000066400000000000000000000016661340547247200164430ustar00rootroot00000000000000# rcov generated coverage # rdoc generated rdoc # yard generated doc .yardoc log # bundler .bundle # jeweler generated pkg # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: # # * Create a file at ~/.gitignore # * Include files you want ignored # * Run: git config --global core.excludesfile ~/.gitignore # # After doing this, these files will be ignored in all your git projects, # saving you from having to 'pollute' every project you touch with them # # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line) # # For MacOS: # #.DS_Store # For TextMate #*.tmproj #tmtags # For emacs: #*~ #\#* #.\#* # For vim: #*.swp # For redcar: #.redcar # For rubinius: #*.rbc .rvmrc .ruby-version Gemfile.lock gemfiles/*.lock .DS_Store /spec/dummy/app/assets/javascripts/routes.js /spec/dummy/logs /spec/dummy/tmp ruby-js-routes-1.4.4/.rspec000066400000000000000000000000101340547247200155460ustar00rootroot00000000000000--color ruby-js-routes-1.4.4/.travis.yml000066400000000000000000000027121340547247200165550ustar00rootroot00000000000000language: ruby cache: bundler before_install: - gem install bundler # need for jruby and ruby-head rvm: - 2.0 - 2.1 - 2.2.5 - 2.3.1 - 2.4.1 - jruby-19mode - ruby-head - jruby-head gemfile: - gemfiles/rails32.gemfile - gemfiles/rails40_sprockets_2.gemfile - gemfiles/rails40_sprockets_3.gemfile - gemfiles/rails41_sprockets_2.gemfile - gemfiles/rails41_sprockets_3.gemfile - gemfiles/rails42_sprockets_2.gemfile - gemfiles/rails42_sprockets_3.gemfile - gemfiles/rails50_sprockets_3.gemfile - gemfiles/rails51_sprockets_3.gemfile sudo: false notifications: email: - agresso@gmail.com branches: only: - master matrix: allow_failures: - rvm: jruby-19mode - rvm: ruby-head - rvm: jruby-head exclude: - rvm: 2.0 gemfile: gemfiles/rails50_sprockets_3.gemfile - rvm: 2.1 gemfile: gemfiles/rails50_sprockets_3.gemfile - rvm: 2.0 gemfile: gemfiles/rails51_sprockets_3.gemfile - rvm: 2.1 gemfile: gemfiles/rails51_sprockets_3.gemfile - rvm: 2.4.1 gemfile: gemfiles/rails40_sprockets_2.gemfile # Segmentation fault (core dumped) for 2.4 - rvm: 2.4.1 gemfile: gemfiles/rails40_sprockets_3.gemfile # Segmentation fault (core dumped) for 2.4 - rvm: 2.4.1 gemfile: gemfiles/rails41_sprockets_2.gemfile # Segmentation fault (core dumped) for 2.4 - rvm: 2.4.1 gemfile: gemfiles/rails41_sprockets_3.gemfile # Segmentation fault (core dumped) for 2.4 ruby-js-routes-1.4.4/Appraisals000066400000000000000000000010361340547247200164640ustar00rootroot00000000000000appraise "rails32" do gem "railties", "~> 3.2.22.5" gem 'tzinfo' end def define_appraisal(rails, version, sprockets) sprockets.each do |sprocket| appraise "#{rails}-sprockets-#{sprocket}" do gem "railties", "~> #{version}" gem "sprockets", "~> #{sprocket}.0" end end end [ [:rails40, '4.0.13', [2, 3]], [:rails41, '4.1.16', [2, 3]], [:rails42, '4.2.9', [2, 3]], [:rails50, '5.0.5', [3]], [:rails51, '5.1.3', [3]] ].each do |name, version, sprockets| define_appraisal(name, version, sprockets) end ruby-js-routes-1.4.4/CHANGELOG.md000066400000000000000000000100411340547247200162470ustar00rootroot00000000000000## master * More informative stack trace for ParameterMissing error #235 ## v1.4.3 * Proper implementation of the :subdomain option in routes generation ## v1.4.2 * Added JsRoutes namespace to Engine #230 ## v1.4.1 * Fixed bug when js-routes is used in envs without window.location #224 ## v1.4.0 * __breaking change!__ Implemented Routes.config() and Routes.configure instead of Routes.defaults New methods support 4 options at the moment: ``` js Routes.configuration(); // => /* { prefix: "", default_url_options: {}, special_options_key: '_options', serializer: function(...) { ... } } */ Routes.configure({ prefix: '/app', default_url_options: {format: 'json'}, special_options_key: '_my_options_key', serializer: function(...) { ... } }); ``` ## v1.3.3 * Improved optional parameters support #216 ## v1.3.2 * Added `application` option #214 ## v1.3.1 * Raise error object with id null passed as route paramter #209 * Sprockets bugfixes #212 ## v1.3.0 * Introduce the special _options key. Fixes #86 ## v1.2.9 * Fixed deprecation varning on Sprockets 3.7 ## v1.2.8 * Bugfix warning on Sprockets 4.0 #202 ## v1.2.7 * Drop support 1.9.3 * Add helper for indexOf, if no native implementation in JS engine * Add sprockets3 compatibility * Bugfix domain defaults to path #197 ## v1.2.6 * Use default prefix from `Rails.application.config.relative_url_root` #186 * Bugfix route globbing with optional fragments bug #191 ## v1.2.5 * Bugfix subdomain default parameter in routes #184 * Bugfix infinite recursion in some specific route sets #183 ## v1.2.4 * Additional bugfixes to support all versions of Sprockets: 2.x and 3.x ## v1.2.3 * Sprockets ~= 3.0 support ## v1.2.2 * Sprockets ~= 3.0 support * Support default parameters specified in route.rb file ## v1.2.1 * Fixes for Rails 5 ## v1.2.0 * Support host, port and protocol inline parameters * Support host, port and protocol parameters given to a route explicitly * Remove all incompatibilities between actiondispatch and js-routes in handling route URLs ## v1.1.2 * Bugfix support nested object null parameters #164 * Bugfix support for nested optional parameters #162 #163 ## v1.1.1 * Bugfix regression in serialisation on blank strings caused by [#155](https://github.com/railsware/js-routes/pull/155/files) ## v1.1.0 * Ensure routes are loaded, prior to generating them [#148](https://github.com/railsware/js-routes/pull/148) * Use `flat_map` rather than `map{...}.flatten` [#149](https://github.com/railsware/js-routes/pull/149) * URL escape routes.rb url to fix bad URI(is not URI?) error [#150](https://github.com/railsware/js-routes/pull/150) * Fix for rails 5 - test rails-edge on travis allowing failure [#151](https://github.com/railsware/js-routes/pull/151) * Adds `serializer` option [#155](https://github.com/railsware/js-routes/pull/155/files) ## v1.0.1 * Support sprockets-3 * Performance optimization of include/exclude options ## v1.0.0 * Add the compact mode [#125](https://github.com/railsware/js-routes/pull/125) * Add support for host, protocol, and port configuration [#137](https://github.com/railsware/js-routes/pull/137) * Routes path specs [#135](https://github.com/railsware/js-routes/pull/135) * Support Rails 4.2 and Ruby 2.2 [#140](https://github.com/railsware/js-routes/pull/140) ## v0.9.9 * Bugfix Rails Engine subapplication route generation when they are nested [#120](https://github.com/railsware/js-routes/pull/120) ## v0.9.8 * Support AMD/Require.js [#111](https://github.com/railsware/js-routes/pull/111) * Support trailing slash [#106](https://github.com/railsware/js-routes/pull/106) ## v0.9.7 * Depend on railties [#97](https://github.com/railsware/js-routes/pull/97) * Fix typeof error for IE [#95](https://github.com/railsware/js-routes/pull/95) * Fix testing on ruby-head [#92](https://github.com/railsware/js-routes/pull/92) * Correct thread safety issue in js-routes generation [#90](https://github.com/railsware/js-routes/pull/90) * Use the `of` operator to detect for `to_param` and `id` in objects [#87](https://github.com/railsware/js-routes/pull/87) ruby-js-routes-1.4.4/Gemfile000066400000000000000000000001351340547247200157340ustar00rootroot00000000000000source "http://rubygems.org" # Specify your gem's dependencies in js-routes.gemspec gemspec ruby-js-routes-1.4.4/LICENSE.txt000066400000000000000000000020411340547247200162620ustar00rootroot00000000000000Copyright (c) 2011 Bogdan Gusiev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-js-routes-1.4.4/Rakefile000066400000000000000000000015711340547247200161130ustar00rootroot00000000000000# encoding: utf-8 require 'rubygems' require 'bundler' begin Bundler.setup(:default, :development) rescue Bundler::BundlerError => e $stderr.puts e.message $stderr.puts "Run `bundle install` to install missing gems" exit e.status_code end require 'bundler/gem_tasks' require 'rspec/core' require 'rspec/core/rake_task' require 'appraisal' load "rails/tasks/routes.rake" RSpec::Core::RakeTask.new(:spec) task :test_all => :appraisal # test all rails task :default => :spec namespace :spec do desc "Print all routes defined in test env" task :routes do require './spec/spec_helper' require 'action_dispatch/routing/inspector' draw_routes all_routes = Rails.application.routes.routes inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes) puts inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, ENV['CONTROLLER']) end end ruby-js-routes-1.4.4/Readme.md000066400000000000000000000232431340547247200161650ustar00rootroot00000000000000# JsRoutes [![Build Status](https://travis-ci.org/railsware/js-routes.svg?branch=master)](https://travis-ci.org/railsware/js-routes) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Frailsware%2Fjs-routes.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Frailsware%2Fjs-routes?ref=badge_shield) Generates javascript file that defines all Rails named routes as javascript helpers ## Intallation Your Rails Gemfile: ``` ruby gem "js-routes" ``` ### Basic Setup Require js routes file in `application.js` or other bundle ``` js //= require js-routes ``` Also in order to flush asset pipeline cache sometimes you might need to run: ``` sh rake tmp:cache:clear ``` This cache is not flushed on server restart in development environment. **Important:** If routes.js file is not updated after some configuration change you need to run this rake task again. ### Advanced Setup If you need to customize routes file create initializer, like `config/initializers/jsroutes.rb`: ``` ruby JsRoutes.setup do |config| config.option = value end ``` Or make a more dynamic configuration in JavaScript, but only specific options support the possibility of such configuration(see the list below): ``` js Routes.configure({ option: value }); Routes.config(); // current config ``` Available options: * `default_url_options` - default parameters used when generating URLs * Option is configurable at JS level with `Routes.configure()` * Example: {:format => "json", :trailing\_slash => true, :protocol => "https", :subdomain => "api", :host => "example.com", :port => 3000} * Default: {} * `exclude` - Array of regexps to exclude from js routes. * Default: [] * The regexp applies only to the name before the `_path` suffix, eg: you want to match exactly `settings_path`, the regexp should be `/^settings$/` * `include` - Array of regexps to include in js routes. * Default: [] * The regexp applies only to the name before the `_path` suffix, eg: you want to match exactly `settings_path`, the regexp should be `/^settings$/` * `namespace` - global object used to access routes. * Supports nested namespace like `MyProject.routes` * Default: `Routes` * `prefix` - String representing a url path to prepend to all paths. * Option is configurable at JS level with `Routes.configure()` * Example: `http://yourdomain.com`. This will cause route helpers to generate full path only. * Default: `Rails.application.config.relative_url_root` * `camel_case` (version >= 0.8.8) - Generate camel case route names. * Default: false * `url_links` (version >= 0.8.9) - Generate `*_url` helpers (in addition to the default `*_path` helpers). * Example: true * Default: false * Note: generated URLs will first use the protocol, host, and port options specified in the route definition. Otherwise, the URL will be based on the option specified in the `default_url_options` config. If no default option has been set, then the URL will fallback to the current URL based on `window.location`. * `compact` (version > 0.9.9) - Remove `_path` suffix in path routes(`*_url` routes stay untouched if they were enabled) * Default: false * Sample route call when option is set to true: Routes.users() => `/users` * `serializer` (version >= 1.1.0) - Puts a JS function here that serializes a Javascript Hash object into URL paramters: `{a: 1, b: 2} => "a=1&b=2"`. * Default: `nil`. Uses built-in serializer * Option is configurable at JS level with `Routes.configure()` * Example: `jQuery.param` - use jQuery's serializer algorithm. You can attach serialize function from your favorite AJAX framework. * Example: `MyApp.custom_serialize` - use completely custom serializer of your application. * `special_options_key` - a special key that helps js-routes to destinguish serialized model from options hash * This option is required because JS doesn't provide a difference between an object and a hash * Option is configurable at JS level with `Routes.configure()` * Default: `_options` * `application` - a key to specify which rails engine you want to generate routes too. * This option allows to only generate routes for a specific rails engine, that is mounted into routes instead of all Rails app routes * Default: `Rails.application` ### Very Advanced Setup In case you need multiple route files for different parts of your application, you have to create the files manually. If your application has an `admin` and an `application` namespace for example: ``` # app/assets/javascripts/admin/routes.js.erb <%= JsRoutes.generate(namespace: "AdminRoutes", include: /admin/) %> # app/assets/javascripts/admin.js.coffee #= require admin/routes ``` ``` # app/assets/javascripts/application/routes.js.erb <%= JsRoutes.generate(namespace: "AppRoutes", exclude: /admin/) %> # app/assets/javascripts/application.js.coffee #= require application/routes ``` In order to generate the routes JS code to a string: ```ruby routes_js = JsRoutes.generate(options) ``` If you want to generate the routes files outside of the asset pipeline, you can use `JsRoutes.generate!`: ``` ruby path = "app/assets/javascripts" JsRoutes.generate!("#{path}/app_routes.js", :namespace => "AppRoutes", :exclude => [/^admin_/, /^api_/]) JsRoutes.generate!("#{path}/adm_routes.js", :namespace => "AdmRoutes", :include => /^admin_/) JsRoutes.generate!("#{path}/api_routes.js", :namespace => "ApiRoutes", :include => /^api_/, :default_url_options => {:format => "json"}) ``` ### Rails relative URL root If you've installed your application in a sub-path or sub-URI of your server instead of at the root, you need to set the `RAILS_RELATIVE_URL_ROOT` environment variable to the correct path prefix for your application when you precompile assets. Eg., if your application's base URL is "https://appl.example.com/Application1", the command to precompile assets would be: ``` RAILS_RELATIVE_URL_ROOT=/Application1 RAILS_ENV=production bundle exec rake assets:precompile ``` The environment variable is only needed for precompilation of assets, at any other time (eg. when assets are compiled on-the-fly as in the development environment) Rails will set the relative URL root correctly on it's own. ## Usage Configuration above will create a nice javascript file with `Routes` object that has all the rails routes available: ``` js Routes.users_path() // => "/users" Routes.user_path(1) // => "/users/1" Routes.user_path(1, {format: 'json'}) // => "/users/1.json" Routes.user_path(1, {anchor: 'profile'}) // => "/users/1#profile" Routes.new_user_project_path(1, {format: 'json'}) // => "/users/1/projects/new.json" Routes.user_project_path(1,2, {q: 'hello', custom: true}) // => "/users/1/projects/2?q=hello&custom=true" Routes.user_project_path(1,2, {hello: ['world', 'mars']}) // => "/users/1/projects/2?hello%5B%5D=world&hello%5B%5D=mars" ``` Using serialized object as route function arguments: ``` js var google = {id: 1, name: "Google"}; Routes.company_path(google) // => "/companies/1" var google = {id: 1, name: "Google", to_param: "google"}; Routes.company_path(google) // => "/companies/google" ``` In order to make routes helpers available globally: ``` js jQuery.extend(window, Routes) ``` ## Get spec of routes and required params Possible to get `spec` of route by function `toString`: ```js Routes.users_path.toString() // => "/users(.:format)" Routes.user_path.toString() // => "/users/:id(.:format)" ``` This function allow to get the same `spec` for route, if you will get string representation of the route function: ```js '' + Routes.users_path // => "/users(.:format)", a string representation of the object '' + Routes.user_path // => "/users/:id(.:format)" ``` Route function also contain inside attribute `required_params` required param names as array: ```js Routes.users_path.required_params // => [] Routes.user_path.required_params // => ['id'] ``` ## Rails Compatibilities JsRoutes ties to be as close as possible to rails behaviour in all aspects of routing API. Please make and issue in case of any incomtibilities found outside of described below. ### Object and Hash distinction issue Sometimes the destinction between JS Hash and Object can not be found by js-routes. In this case you would need to pass a special key to help: ``` js Routes.company_project_path({company_id: 1, id: 2}) // => Not Enough parameters Routes.company_project_path({company_id: 1, id: 2, _options: true}) // => "/companies/1/projects/2" ``` ## What about security? js-routes itself do not have security holes. It makes URLs without access protection more reachable by potential attacker. In order to prevent this use `:exclude` option for sensitive urls like `/admin_/` ## Spork When using Spork and `Spork.trap_method(Rails::Application::RoutesReloader, :reload!)` you should also do: ``` ruby Spork.trap_method(JsRoutes, :generate!) ``` ## JS-Routes and heroku Heroku environment has a specific problems with setup. It is impossible to use asset pipeline in this environment. You should use "Very Advanced Setup" schema in this case. For example create routes.js.erb in assets folder with needed content: ``` erb <%= JsRoutes.generate(options) %> ``` This should just work. ## Advantages over alternatives There are some alternatives available. Most of them has only basic feature and don't reach the level of quality I accept. Advantages of this one are: * Rails 3-5 support * Rich options set * Full rails compatibility * Support Rails `#to_param` convention for seo optimized paths * Well tested #### Thanks to [Contributors](https://github.com/railsware/js-routes/contributors) #### Have fun ## License [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Frailsware%2Fjs-routes.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Frailsware%2Fjs-routes?ref=badge_large)ruby-js-routes-1.4.4/app/000077500000000000000000000000001340547247200152225ustar00rootroot00000000000000ruby-js-routes-1.4.4/app/assets/000077500000000000000000000000001340547247200165245ustar00rootroot00000000000000ruby-js-routes-1.4.4/app/assets/javascripts/000077500000000000000000000000001340547247200210555ustar00rootroot00000000000000ruby-js-routes-1.4.4/app/assets/javascripts/js-routes.js.erb000066400000000000000000000001311340547247200241100ustar00rootroot00000000000000<%# encoding: UTF-8 %> <%= JsRoutes.assert_usable_configuration! && JsRoutes.generate %> ruby-js-routes-1.4.4/gemfiles/000077500000000000000000000000001340547247200162355ustar00rootroot00000000000000ruby-js-routes-1.4.4/gemfiles/rails32.gemfile000066400000000000000000000002111340547247200210400ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 3.2.22.5" gem "tzinfo" gemspec :path => "../" ruby-js-routes-1.4.4/gemfiles/rails40_sprockets_2.gemfile000066400000000000000000000002241340547247200233610ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.0.13" gem "sprockets", "~> 2.0" gemspec :path => "../" ruby-js-routes-1.4.4/gemfiles/rails40_sprockets_3.gemfile000066400000000000000000000002241340547247200233620ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.0.13" gem "sprockets", "~> 3.0" gemspec :path => "../" ruby-js-routes-1.4.4/gemfiles/rails41_sprockets_2.gemfile000066400000000000000000000002241340547247200233620ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.1.16" gem "sprockets", "~> 2.0" gemspec :path => "../" ruby-js-routes-1.4.4/gemfiles/rails41_sprockets_3.gemfile000066400000000000000000000002241340547247200233630ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.1.16" gem "sprockets", "~> 3.0" gemspec :path => "../" ruby-js-routes-1.4.4/gemfiles/rails42_sprockets_2.gemfile000066400000000000000000000002231340547247200233620ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.2.9" gem "sprockets", "~> 2.0" gemspec :path => "../" ruby-js-routes-1.4.4/gemfiles/rails42_sprockets_3.gemfile000066400000000000000000000002231340547247200233630ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.2.9" gem "sprockets", "~> 3.0" gemspec :path => "../" ruby-js-routes-1.4.4/gemfiles/rails50_sprockets_3.gemfile000066400000000000000000000002231340547247200233620ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 5.0.5" gem "sprockets", "~> 3.0" gemspec :path => "../" ruby-js-routes-1.4.4/gemfiles/rails51_sprockets_3.gemfile000066400000000000000000000002231340547247200233630ustar00rootroot00000000000000# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 5.1.3" gem "sprockets", "~> 3.0" gemspec :path => "../" ruby-js-routes-1.4.4/js-routes.gemspec000066400000000000000000000025311340547247200177430ustar00rootroot00000000000000# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'js_routes/version' Gem::Specification.new do |s| s.name = %q{js-routes} s.version = JsRoutes::VERSION s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bogdan Gusiev"] s.description = %q{Generates javascript file that defines all Rails named routes as javascript helpers} s.email = %q{agresso@gmail.com} s.extra_rdoc_files = [ "LICENSE.txt" ] s.files = `git ls-files`.split("\n") s.homepage = %q{http://github.com/railsware/js-routes} s.licenses = ["MIT"] s.require_paths = ["lib"] s.summary = %q{Brings Rails named routes to javascript} s.add_runtime_dependency(%q, [">= 3.2"]) s.add_runtime_dependency(%q) s.add_development_dependency(%q, [">= 3.0.0"]) s.add_development_dependency(%q, [">= 1.1.0"]) s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 0.5.2"]) if defined?(JRUBY_VERSION) s.add_development_dependency(%q, [">= 2.0.4"]) else s.add_development_dependency(%q) s.add_development_dependency(%q) s.add_development_dependency(%q, [">= 0.12.3"]) end end ruby-js-routes-1.4.4/lib/000077500000000000000000000000001340547247200152105ustar00rootroot00000000000000ruby-js-routes-1.4.4/lib/js-routes.rb000066400000000000000000000000241340547247200174640ustar00rootroot00000000000000require 'js_routes' ruby-js-routes-1.4.4/lib/js_routes.rb000066400000000000000000000177311340547247200175630ustar00rootroot00000000000000require 'uri' require 'js_routes/engine' if defined?(Rails) require 'js_routes/version' class JsRoutes # # OPTIONS # DEFAULT_PATH = File.join('app','assets','javascripts','routes.js') DEFAULTS = { namespace: "Routes", exclude: [], include: //, file: DEFAULT_PATH, prefix: -> { Rails.application.config.relative_url_root || "" }, url_links: false, camel_case: false, default_url_options: {}, compact: false, serializer: nil, special_options_key: "_options", application: -> { Rails.application } } NODE_TYPES = { GROUP: 1, CAT: 2, SYMBOL: 3, OR: 4, STAR: 5, LITERAL: 6, SLASH: 7, DOT: 8 } LAST_OPTIONS_KEY = "options".freeze FILTERED_DEFAULT_PARTS = [:controller, :action] URL_OPTIONS = [:protocol, :domain, :host, :port, :subdomain] class Configuration < Struct.new(*DEFAULTS.keys) def initialize(attributes = nil) assign(DEFAULTS) return unless attributes assign(attributes) end def assign(attributes) attributes.each do |attribute, value| value = value.call if value.is_a?(Proc) send(:"#{attribute}=", value) end self end def [](attribute) send(attribute) end def merge(attributes) clone.assign(attributes) end def to_hash Hash[*members.zip(values).flatten(1)].symbolize_keys end end # # API # class << self def setup(&block) configuration.tap(&block) if block end def options ActiveSupport::Deprecation.warn('JsRoutes.options method is deprecated use JsRoutes.configuration instead') configuration end def configuration @configuration ||= Configuration.new end def generate(opts = {}) new(opts).generate end def generate!(file_name=nil, opts = {}) if file_name.is_a?(Hash) opts = file_name file_name = opts[:file] end new(opts).generate!(file_name) end # Under rails 3.1.1 and higher, perform a check to ensure that the # full environment will be available during asset compilation. # This is required to ensure routes are loaded. def assert_usable_configuration! if 3 == Rails::VERSION::MAJOR && !Rails.application.config.assets.initialize_on_precompile raise("Cannot precompile js-routes unless environment is initialized. Please set config.assets.initialize_on_precompile to true.") end true end def json(string) ActiveSupport::JSON.encode(string) end end # # Implementation # def initialize(options = {}) @configuration = self.class.configuration.merge(options) end def generate # Ensure routes are loaded. If they're not, load them. if named_routes.to_a.empty? && application.respond_to?(:reload_routes!) application.reload_routes! end { "GEM_VERSION" => JsRoutes::VERSION, "ROUTES" => js_routes, "DEPRECATED_BEHAVIOR" => Rails.version < "4", "NODE_TYPES" => json(NODE_TYPES), "APP_CLASS" => application.class.to_s, "NAMESPACE" => json(@configuration.namespace), "DEFAULT_URL_OPTIONS" => json(@configuration.default_url_options), "PREFIX" => json(@configuration.prefix), "SPECIAL_OPTIONS_KEY" => json(@configuration.special_options_key), "SERIALIZER" => @configuration.serializer || json(nil), }.inject(File.read(File.dirname(__FILE__) + "/routes.js")) do |js, (key, value)| js.gsub!(key, value.to_s) end end def generate!(file_name = nil) # Some libraries like Devise do not yet loaded their routes so we will wait # until initialization process finish # https://github.com/railsware/js-routes/issues/7 Rails.configuration.after_initialize do file_name ||= self.class.configuration['file'] File.open(Rails.root.join(file_name), 'w') do |f| f.write generate end end end protected def application @configuration.application end def named_routes application.routes.named_routes.to_a end def js_routes js_routes = named_routes.sort_by(&:first).flat_map do |_, route| [build_route_if_match(route)] + mounted_app_routes(route) end.compact "{\n" + js_routes.join(",\n") + "}\n" end def mounted_app_routes(route) rails_engine_app = get_app_from_route(route) if rails_engine_app.respond_to?(:superclass) && rails_engine_app.superclass == Rails::Engine && !route.path.anchored rails_engine_app.routes.named_routes.map do |_, engine_route| build_route_if_match(engine_route, route) end else [] end end def get_app_from_route(route) # rails engine in Rails 4.2 use additional ActionDispatch::Routing::Mapper::Constraints, which contain app if route.app.respond_to?(:app) && route.app.respond_to?(:constraints) route.app.app else route.app end end def build_route_if_match(route, parent_route=nil) if any_match?(route, parent_route, @configuration[:exclude]) || !any_match?(route, parent_route, @configuration[:include]) nil else build_js(route, parent_route) end end def any_match?(route, parent_route, matchers) full_route = [parent_route.try(:name), route.name].compact.join('_') matchers = Array(matchers) matchers.any? {|regex| full_route =~ regex} end def build_js(route, parent_route) name = [parent_route.try(:name), route.name].compact route_name = generate_route_name(name, (:path unless @configuration[:compact])) parent_spec = parent_route.try(:path).try(:spec) route_arguments = route_js_arguments(route, parent_spec) url_link = generate_url_link(name, route_name, route_arguments, route) _ = <<-JS.strip! // #{name.join('.')} => #{parent_spec}#{route.path.spec} // function(#{build_params(route.required_parts)}) #{route_name}: Utils.route(#{route_arguments})#{",\n" + url_link if url_link.length > 0} JS end def route_js_arguments(route, parent_spec) required_parts = route.required_parts parts_table = route.parts.each_with_object({}) do |part, hash| hash[part] = required_parts.include?(part) end default_options = route.defaults.select do |part, _| FILTERED_DEFAULT_PARTS.exclude?(part) && URL_OPTIONS.include?(part) || parts_table[part] end [ # JS objects don't preserve the order of properties which is crucial, # so array is a better choice. parts_table.to_a, default_options, serialize(route.path.spec, parent_spec) ].map do |argument| json(argument) end.join(", ") end def generate_url_link(name, route_name, route_arguments, route) return "" unless @configuration[:url_links] <<-JS.strip! #{generate_route_name(name, :url)}: Utils.route(#{route_arguments}, true) JS end def generate_route_name(name, suffix) route_name = name.join('_') route_name << "_#{ suffix }" if suffix @configuration[:camel_case] ? route_name.camelize(:lower) : route_name end def json(string) self.class.json(string) end def build_params(required_parts) params = required_parts + [LAST_OPTIONS_KEY] params.join(", ") end # This function serializes Journey route into JSON structure # We do not use Hash for human readable serialization # And preffer Array serialization because it is shorter. # Routes.js file will be smaller. def serialize(spec, parent_spec=nil) return nil unless spec return spec.tr(':', '') if spec.is_a?(String) result = serialize_spec(spec, parent_spec) if parent_spec && result[1].is_a?(String) result = [ # We encode node symbols as integer # to reduce the routes.js file size NODE_TYPES[:CAT], serialize_spec(parent_spec), result ] end result end def serialize_spec(spec, parent_spec=nil) [ NODE_TYPES[spec.type], serialize(spec.left, parent_spec), spec.respond_to?(:right) && serialize(spec.right) ] end end ruby-js-routes-1.4.4/lib/js_routes/000077500000000000000000000000001340547247200172255ustar00rootroot00000000000000ruby-js-routes-1.4.4/lib/js_routes/engine.rb000066400000000000000000000045111340547247200210200ustar00rootroot00000000000000class JsRoutes class SprocketsExtension def initialize(filename, &block) @filename = filename @source = block.call end def render(context, empty_hash_wtf) self.class.run(@filename, @source, context) end def self.run(filename, source, context) if context.logical_path == 'js-routes' routes = Rails.root.join('config', 'routes.rb').to_s context.depend_on(routes) end source end def self.call(input) filename = input[:filename] source = input[:data] context = input[:environment].context_class.new(input) result = run(filename, source, context) context.metadata.merge(data: result) end end class Engine < ::Rails::Engine require 'sprockets/version' v2 = Gem::Dependency.new('', ' ~> 2') vgte3 = Gem::Dependency.new('', ' >= 3') sprockets_version = Gem::Version.new(::Sprockets::VERSION).release initializer_args = case sprockets_version when -> (v) { v2.match?('', v) } { after: "sprockets.environment" } when -> (v) { vgte3.match?('', v) } { after: :engines_blank_point, before: :finisher_hook } else raise StandardError, "Sprockets version #{sprockets_version} is not supported" end is_running_rails = defined?(Rails) && Rails.respond_to?(:version) is_running_rails_32 = is_running_rails && Rails.version.match(/3\.2/) initializer 'js-routes.dependent_on_routes', initializer_args do case sprockets_version when -> (v) { v2.match?('', v) }, -> (v) { vgte3.match?('', v) } # It seems rails 3.2 is not working if # `Rails.application.config.assets.configure` is used for # registering preprocessor if is_running_rails_32 Rails.application.assets.register_preprocessor( "application/javascript", SprocketsExtension, ) else # Other rails version, assumed newer Rails.application.config.assets.configure do |config| config.register_preprocessor( "application/javascript", SprocketsExtension, ) end end else raise StandardError, "Sprockets version #{sprockets_version} is not supported" end end end end ruby-js-routes-1.4.4/lib/js_routes/version.rb000066400000000000000000000000471340547247200212400ustar00rootroot00000000000000class JsRoutes VERSION = "1.4.4" end ruby-js-routes-1.4.4/lib/routes.js000066400000000000000000000403331340547247200170720ustar00rootroot00000000000000/* File generated by js-routes GEM_VERSION Based on Rails routes of APP_CLASS */ (function() { var DeprecatedBehavior, NodeTypes, ParameterMissing, ReservedOptions, SpecialOptionsKey, Utils, root, hasProp = {}.hasOwnProperty, slice = [].slice; root = typeof exports !== "undefined" && exports !== null ? exports : this; function ParameterMissing(message, fileName, lineNumber) { var instance = new Error(message, fileName, lineNumber); if(Object.setPrototypeOf) { Object.setPrototypeOf(instance, Object.getPrototypeOf(this)); } else { instance.__proto__ = this.__proto__; } if (Error.captureStackTrace) { Error.captureStackTrace(instance, ParameterMissing); } return instance; } ParameterMissing.prototype = Object.create(Error.prototype, { constructor: { value: Error, enumerable: false, writable: true, configurable: true } }); if (Object.setPrototypeOf){ Object.setPrototypeOf(ParameterMissing, Error); } else { ParameterMissing.__proto__ = Error; } NodeTypes = NODE_TYPES; SpecialOptionsKey = SPECIAL_OPTIONS_KEY; DeprecatedBehavior = DEPRECATED_BEHAVIOR; ReservedOptions = ['anchor', 'trailing_slash', 'subdomain', 'host', 'port', 'protocol']; Utils = { configuration: { prefix: PREFIX, default_url_options: DEFAULT_URL_OPTIONS, special_options_key: SPECIAL_OPTIONS_KEY, serializer: SERIALIZER }, default_serializer: function(object, prefix) { var element, i, j, key, len, prop, s; if (prefix == null) { prefix = null; } if (object == null) { return ""; } if (!prefix && !(this.get_object_type(object) === "object")) { throw new Error("Url parameters should be a javascript hash"); } s = []; switch (this.get_object_type(object)) { case "array": for (i = j = 0, len = object.length; j < len; i = ++j) { element = object[i]; s.push(this.default_serializer(element, prefix + "[]")); } break; case "object": for (key in object) { if (!hasProp.call(object, key)) continue; prop = object[key]; if ((prop == null) && (prefix != null)) { prop = ""; } if (prop != null) { if (prefix != null) { key = prefix + "[" + key + "]"; } s.push(this.default_serializer(prop, key)); } } break; default: if (object != null) { s.push((encodeURIComponent(prefix.toString())) + "=" + (encodeURIComponent(object.toString()))); } } if (!s.length) { return ""; } return s.join("&"); }, serialize: function(object) { var custom_serializer; custom_serializer = this.configuration.serializer; if ((custom_serializer != null) && this.get_object_type(custom_serializer) === "function") { return custom_serializer(object); } else { return this.default_serializer(object); } }, clean_path: function(path) { var last_index; path = path.split("://"); last_index = path.length - 1; path[last_index] = path[last_index].replace(/\/+/g, "/"); return path.join("://"); }, extract_options: function(number_of_params, args) { var last_el, options; last_el = args[args.length - 1]; if ((args.length > number_of_params && last_el === void 0) || ((last_el != null) && "object" === this.get_object_type(last_el) && !this.looks_like_serialized_model(last_el))) { options = args.pop() || {}; delete options[this.configuration.special_options_key]; return options; } else { return {}; } }, looks_like_serialized_model: function(object) { return !object[this.configuration.special_options_key] && ("id" in object || "to_param" in object); }, path_identifier: function(object) { var property; if (object === 0) { return "0"; } if (!object) { return ""; } property = object; if (this.get_object_type(object) === "object") { if ("to_param" in object) { if (object.to_param == null) { throw new ParameterMissing("Route parameter missing: to_param"); } property = object.to_param; } else if ("id" in object) { if (object.id == null) { throw new ParameterMissing("Route parameter missing: id"); } property = object.id; } else { property = object; } if (this.get_object_type(property) === "function") { property = property.call(object); } } return property.toString(); }, clone: function(obj) { var attr, copy, key; if ((obj == null) || "object" !== this.get_object_type(obj)) { return obj; } copy = obj.constructor(); for (key in obj) { if (!hasProp.call(obj, key)) continue; attr = obj[key]; copy[key] = attr; } return copy; }, merge: function() { var tap, xs; xs = 1 <= arguments.length ? slice.call(arguments, 0) : []; tap = function(o, fn) { fn(o); return o; }; if ((xs != null ? xs.length : void 0) > 0) { return tap({}, function(m) { var j, k, len, results, v, x; results = []; for (j = 0, len = xs.length; j < len; j++) { x = xs[j]; results.push((function() { var results1; results1 = []; for (k in x) { v = x[k]; results1.push(m[k] = v); } return results1; })()); } return results; }); } }, normalize_options: function(parts, required_parts, default_options, actual_parameters) { var i, j, key, len, options, part, parts_options, result, route_parts, url_parameters, use_all_parts, value; options = this.extract_options(parts.length, actual_parameters); if (actual_parameters.length > parts.length) { throw new Error("Too many parameters provided for path"); } use_all_parts = DeprecatedBehavior || actual_parameters.length > required_parts.length; parts_options = {}; for (key in options) { if (!hasProp.call(options, key)) continue; use_all_parts = true; if (this.indexOf(parts, key) >= 0) { parts_options[key] = value; } } options = this.merge(this.configuration.default_url_options, default_options, options); result = {}; url_parameters = {}; result['url_parameters'] = url_parameters; for (key in options) { if (!hasProp.call(options, key)) continue; value = options[key]; if (this.indexOf(ReservedOptions, key) >= 0) { result[key] = value; } else { url_parameters[key] = value; } } route_parts = use_all_parts ? parts : required_parts; i = 0; for (j = 0, len = route_parts.length; j < len; j++) { part = route_parts[j]; if (i < actual_parameters.length) { if (!parts_options.hasOwnProperty(part)) { url_parameters[part] = actual_parameters[i]; ++i; } } } return result; }, build_route: function(parts, required_parts, default_options, route, full_url, args) { var options, parameters, result, url, url_params; args = Array.prototype.slice.call(args); options = this.normalize_options(parts, required_parts, default_options, args); parameters = options['url_parameters']; result = "" + (this.get_prefix()) + (this.visit(route, parameters)); url = Utils.clean_path(result); if (options['trailing_slash'] === true) { url = url.replace(/(.*?)[\/]?$/, "$1/"); } if ((url_params = this.serialize(parameters)).length) { url += "?" + url_params; } url += options.anchor ? "#" + options.anchor : ""; if (full_url) { url = this.route_url(options) + url; } return url; }, visit: function(route, parameters, optional) { var left, left_part, right, right_part, type, value; if (optional == null) { optional = false; } type = route[0], left = route[1], right = route[2]; switch (type) { case NodeTypes.GROUP: return this.visit(left, parameters, true); case NodeTypes.STAR: return this.visit_globbing(left, parameters, true); case NodeTypes.LITERAL: case NodeTypes.SLASH: case NodeTypes.DOT: return left; case NodeTypes.CAT: left_part = this.visit(left, parameters, optional); right_part = this.visit(right, parameters, optional); if (optional && ((this.is_optional_node(left[0]) && !left_part) || ((this.is_optional_node(right[0])) && !right_part))) { return ""; } return "" + left_part + right_part; case NodeTypes.SYMBOL: value = parameters[left]; if (value != null) { delete parameters[left]; return this.path_identifier(value); } if (optional) { return ""; } else { throw new ParameterMissing("Route parameter missing: " + left); } break; default: throw new Error("Unknown Rails node type"); } }, is_optional_node: function(node) { return this.indexOf([NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT], node) >= 0; }, build_path_spec: function(route, wildcard) { var left, right, type; if (wildcard == null) { wildcard = false; } type = route[0], left = route[1], right = route[2]; switch (type) { case NodeTypes.GROUP: return "(" + (this.build_path_spec(left)) + ")"; case NodeTypes.CAT: return "" + (this.build_path_spec(left)) + (this.build_path_spec(right)); case NodeTypes.STAR: return this.build_path_spec(left, true); case NodeTypes.SYMBOL: if (wildcard === true) { return "" + (left[0] === '*' ? '' : '*') + left; } else { return ":" + left; } break; case NodeTypes.SLASH: case NodeTypes.DOT: case NodeTypes.LITERAL: return left; default: throw new Error("Unknown Rails node type"); } }, visit_globbing: function(route, parameters, optional) { var left, right, type, value; type = route[0], left = route[1], right = route[2]; if (left.replace(/^\*/i, "") !== left) { route[1] = left = left.replace(/^\*/i, ""); } value = parameters[left]; if (value == null) { return this.visit(route, parameters, optional); } parameters[left] = (function() { switch (this.get_object_type(value)) { case "array": return value.join("/"); default: return value; } }).call(this); return this.visit(route, parameters, optional); }, get_prefix: function() { var prefix; prefix = this.configuration.prefix; if (prefix !== "") { prefix = (prefix.match("/$") ? prefix : prefix + "/"); } return prefix; }, route: function(parts_table, default_options, route_spec, full_url) { var j, len, part, parts, path_fn, ref, required, required_parts; required_parts = []; parts = []; for (j = 0, len = parts_table.length; j < len; j++) { ref = parts_table[j], part = ref[0], required = ref[1]; parts.push(part); if (required) { required_parts.push(part); } } path_fn = function() { return Utils.build_route(parts, required_parts, default_options, route_spec, full_url, arguments); }; path_fn.required_params = required_parts; path_fn.toString = function() { return Utils.build_path_spec(route_spec); }; return path_fn; }, route_url: function(route_defaults) { var hostname, port, protocol, subdomain; if (typeof route_defaults === 'string') { return route_defaults; } hostname = route_defaults.host || Utils.current_host(); if (!hostname) { return ''; } subdomain = route_defaults.subdomain ? route_defaults.subdomain + '.' : ''; protocol = route_defaults.protocol || Utils.current_protocol(); port = route_defaults.port || (!route_defaults.host ? Utils.current_port() : void 0); port = port ? ":" + port : ''; return protocol + "://" + subdomain + hostname + port; }, has_location: function() { return (typeof window !== "undefined" && window !== null ? window.location : void 0) != null; }, current_host: function() { if (this.has_location()) { return window.location.hostname; } else { return null; } }, current_protocol: function() { if (this.has_location() && window.location.protocol !== '') { return window.location.protocol.replace(/:$/, ''); } else { return 'http'; } }, current_port: function() { if (this.has_location() && window.location.port !== '') { return window.location.port; } else { return ''; } }, _classToTypeCache: null, _classToType: function() { var j, len, name, ref; if (this._classToTypeCache != null) { return this._classToTypeCache; } this._classToTypeCache = {}; ref = "Boolean Number String Function Array Date RegExp Object Error".split(" "); for (j = 0, len = ref.length; j < len; j++) { name = ref[j]; this._classToTypeCache["[object " + name + "]"] = name.toLowerCase(); } return this._classToTypeCache; }, get_object_type: function(obj) { if (root.jQuery && (root.jQuery.type != null)) { return root.jQuery.type(obj); } if (obj == null) { return "" + obj; } if (typeof obj === "object" || typeof obj === "function") { return this._classToType()[Object.prototype.toString.call(obj)] || "object"; } else { return typeof obj; } }, indexOf: function(array, element) { if (Array.prototype.indexOf) { return array.indexOf(element); } else { return this.indexOfImplementation(array, element); } }, indexOfImplementation: function(array, element) { var el, i, j, len, result; result = -1; for (i = j = 0, len = array.length; j < len; i = ++j) { el = array[i]; if (el === element) { result = i; } } return result; }, namespace: function(root, namespace, routes) { var index, j, len, part, parts; parts = namespace.split("."); if (parts.length === 0) { return routes; } for (index = j = 0, len = parts.length; j < len; index = ++j) { part = parts[index]; if (index < parts.length - 1) { root = (root[part] || (root[part] = {})); } else { return root[part] = routes; } } }, configure: function(new_config) { return this.configuration = this.merge(this.configuration, new_config); }, config: function() { return this.clone(this.configuration); }, make: function() { var routes; routes = ROUTES; routes.configure = function(config) { return Utils.configure(config); }; routes.config = function() { return Utils.config(); }; Object.defineProperty(routes, 'defaults', { get: function() { throw new Error(NAMESPACE + ".defaults is removed. Use " + NAMESPACE + ".configure() instead."); }, set: function(value) {} }); routes.default_serializer = function(object, prefix) { return Utils.default_serializer(object, prefix); }; return Utils.namespace(root, NAMESPACE, routes); } }; if (typeof define === "function" && define.amd) { define([], function() { return Utils.make(); }); } else { Utils.make(); } }).call(this); ruby-js-routes-1.4.4/lib/routes.js.coffee000066400000000000000000000315751340547247200203300ustar00rootroot00000000000000### File generated by js-routes GEM_VERSION Based on Rails routes of APP_CLASS ### # root is this root = (exports ? this) ParameterMissing = (message, fileName, lineNumber) -> instance = new Error(message, fileName, lineNumber) if Object.setPrototypeOf Object.setPrototypeOf instance, Object.getPrototypeOf(this) else instance.__proto__ = this.__proto__ if Error.captureStackTrace Error.captureStackTrace instance, ParameterMissing instance ParameterMissing.prototype = Object.create(Error.prototype, constructor: value: Error enumerable: false writable: true configurable: true ) if Object.setPrototypeOf Object.setPrototypeOf(ParameterMissing, Error) else ParameterMissing.__proto__ = Error NodeTypes = NODE_TYPES SpecialOptionsKey = SPECIAL_OPTIONS_KEY DeprecatedBehavior = DEPRECATED_BEHAVIOR ReservedOptions = [ 'anchor' 'trailing_slash' 'subdomain' 'host' 'port' 'protocol' ] Utils = configuration: prefix: PREFIX default_url_options: DEFAULT_URL_OPTIONS special_options_key: SPECIAL_OPTIONS_KEY serializer: SERIALIZER default_serializer: (object, prefix = null) -> return "" unless object? if !prefix and !(@get_object_type(object) is "object") throw new Error("Url parameters should be a javascript hash") s = [] switch @get_object_type(object) when "array" for element, i in object s.push @default_serializer(element, prefix + "[]") when "object" for own key, prop of object if !prop? and prefix? prop = "" if prop? key = "#{prefix}[#{key}]" if prefix? s.push @default_serializer(prop, key) else if object? s.push "#{encodeURIComponent(prefix.toString())}=#{encodeURIComponent(object.toString())}" return "" unless s.length s.join("&") serialize: (object) -> custom_serializer = @configuration.serializer if custom_serializer? and @get_object_type(custom_serializer) is "function" custom_serializer(object) else @default_serializer(object) clean_path: (path) -> path = path.split("://") last_index = path.length - 1 path[last_index] = path[last_index].replace(/\/+/g, "/") path.join "://" extract_options: (number_of_params, args) -> last_el = args[args.length - 1] if (args.length > number_of_params and last_el == undefined) or (last_el? and "object" is @get_object_type(last_el) and !@looks_like_serialized_model(last_el)) options = args.pop() || {} delete options[@configuration.special_options_key] options else {} looks_like_serialized_model: (object) -> !object[@configuration.special_options_key] and ("id" of object or "to_param" of object) path_identifier: (object) -> return "0" if object is 0 # null, undefined, false or '' return "" unless object property = object if @get_object_type(object) is "object" if "to_param" of object throw new ParameterMissing("Route parameter missing: to_param") unless object.to_param? property = object.to_param else if "id" of object throw new ParameterMissing("Route parameter missing: id") unless object.id? property = object.id else property = object property = property.call(object) if @get_object_type(property) is "function" property.toString() clone: (obj) -> return obj if !obj? or "object" isnt @get_object_type(obj) copy = obj.constructor() copy[key] = attr for own key, attr of obj copy merge: (xs...) -> tap = (o, fn) -> fn(o); o if xs?.length > 0 tap {}, (m) -> m[k] = v for k, v of x for x in xs normalize_options: (parts, required_parts, default_options, actual_parameters) -> options = @extract_options(parts.length, actual_parameters) if actual_parameters.length > parts.length throw new Error("Too many parameters provided for path") use_all_parts = DeprecatedBehavior or actual_parameters.length > required_parts.length parts_options = {} for own key of options use_all_parts = true if @indexOf(parts, key) >= 0 parts_options[key] = value options = @merge(@configuration.default_url_options, default_options, options) result = {} url_parameters = {} result['url_parameters'] = url_parameters for own key, value of options if @indexOf(ReservedOptions, key) >= 0 result[key] = value else url_parameters[key] = value route_parts = if use_all_parts then parts else required_parts i = 0 for part in route_parts when i < actual_parameters.length unless parts_options.hasOwnProperty(part) url_parameters[part] = actual_parameters[i] ++i result build_route: (parts, required_parts, default_options, route, full_url, args) -> args = Array::slice.call(args) options = @normalize_options(parts, required_parts, default_options, args) parameters = options['url_parameters'] # path result = "#{@get_prefix()}#{@visit(route, parameters)}" url = Utils.clean_path(result) # set trailing_slash url = url.replace(/(.*?)[\/]?$/, "$1/") if options['trailing_slash'] is true # set additional url params if (url_params = @serialize(parameters)).length url += "?#{url_params}" # set anchor url += if options.anchor then "##{options.anchor}" else "" if full_url url = @route_url(options) + url url # # This function is JavaScript impelementation of the # Journey::Visitors::Formatter that builds route by given parameters # from route binary tree. # Binary tree is serialized in the following way: # [node type, left node, right node ] # # @param {Boolean} optional Marks the currently visited branch as optional. # If set to `true`, this method will not throw when encountering # a missing parameter (used in recursive calls). # visit: (route, parameters, optional = false) -> [type, left, right] = route switch type when NodeTypes.GROUP @visit left, parameters, true when NodeTypes.STAR @visit_globbing left, parameters, true when NodeTypes.LITERAL, NodeTypes.SLASH, NodeTypes.DOT left when NodeTypes.CAT left_part = @visit(left, parameters, optional) right_part = @visit(right, parameters, optional) if optional and ((@is_optional_node(left[0]) and not left_part) or ((@is_optional_node(right[0])) and not right_part)) return "" "#{left_part}#{right_part}" when NodeTypes.SYMBOL value = parameters[left] if value? delete parameters[left] return @path_identifier(value) if optional "" # missing parameter else throw new ParameterMissing("Route parameter missing: #{left}") # # I don't know what is this node type # Please send your PR if you do # # when NodeTypes.OR: else throw new Error("Unknown Rails node type") is_optional_node: (node) -> @indexOf([NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT], node) >= 0 # # This method build spec for route # build_path_spec: (route, wildcard=false) -> [type, left, right] = route switch type when NodeTypes.GROUP "(#{@build_path_spec(left)})" when NodeTypes.CAT "#{@build_path_spec(left)}#{@build_path_spec(right)}" when NodeTypes.STAR @build_path_spec(left, true) when NodeTypes.SYMBOL if wildcard is true "#{if left[0] is '*' then '' else '*'}#{left}" else ":#{left}" when NodeTypes.SLASH, NodeTypes.DOT, NodeTypes.LITERAL left # Not sure about this one # when NodeTypes.OR else throw new Error("Unknown Rails node type") # # This method convert value for globbing in right value for rails route # visit_globbing: (route, parameters, optional) -> [type, left, right] = route # fix for rails 4 globbing route[1] = left = left.replace(/^\*/i, "") if left.replace(/^\*/i, "") isnt left value = parameters[left] return @visit(route, parameters, optional) unless value? parameters[left] = switch @get_object_type(value) when "array" value.join("/") else value @visit route, parameters, optional # # This method check and return prefix from options # get_prefix: -> prefix = @configuration.prefix prefix = (if prefix.match("/$") then prefix else "#{prefix}/") if prefix isnt "" prefix # # route function: create route path function and add spec to it # route: (parts_table, default_options, route_spec, full_url) -> required_parts = [] parts = [] for [part, required] in parts_table parts.push(part) required_parts.push(part) if required path_fn = -> Utils.build_route( parts, required_parts, default_options, route_spec, full_url, arguments ) path_fn.required_params = required_parts path_fn.toString = -> Utils.build_path_spec(route_spec) path_fn route_url: (route_defaults) -> return route_defaults if typeof route_defaults == 'string' hostname = route_defaults.host || Utils.current_host() return '' unless hostname subdomain = if route_defaults.subdomain then route_defaults.subdomain + '.' else '' protocol = route_defaults.protocol || Utils.current_protocol() port = route_defaults.port || (Utils.current_port() unless route_defaults.host) port = if port then ":#{port}" else '' protocol + "://" + subdomain + hostname + port has_location: -> window?.location? current_host: -> if @has_location() then window.location.hostname else null current_protocol: () -> if @has_location() && window.location.protocol != '' # location.protocol includes the colon character window.location.protocol.replace(/:$/, '') else 'http' current_port: () -> if @has_location() && window.location.port != '' window.location.port else '' # # This is helper method to define object type. # The typeof operator is probably the biggest design flaw of JavaScript, simply because it's basically completely broken. # # Value Class Type # ------------------------------------- # "foo" String string # new String("foo") String object # 1.2 Number number # new Number(1.2) Number object # true Boolean boolean # new Boolean(true) Boolean object # new Date() Date object # new Error() Error object # [1,2,3] Array object # new Array(1, 2, 3) Array object # new Function("") Function function # /abc/g RegExp object # new RegExp("meow") RegExp object # {} Object object # new Object() Object object # # What is why I use Object.prototype.toString() to know better type of variable. Or use jQuery.type, if it available. # _classToTypeCache used for perfomance cache of types map (underscore at the beginning mean private method - of course it doesn't realy private). # _classToTypeCache: null _classToType: -> return @_classToTypeCache if @_classToTypeCache? @_classToTypeCache = {} for name in "Boolean Number String Function Array Date RegExp Object Error".split(" ") @_classToTypeCache["[object #{name}]"] = name.toLowerCase() @_classToTypeCache get_object_type: (obj) -> return root.jQuery.type(obj) if root.jQuery and root.jQuery.type? return "#{obj}" unless obj? (if typeof obj is "object" or typeof obj is "function" then @_classToType()[Object::toString.call(obj)] or "object" else typeof obj) # indexOf helper indexOf: (array, element) -> if Array::indexOf then array.indexOf(element) else @indexOfImplementation(array, element) indexOfImplementation: (array, element) -> result = -1 (result = i for el, i in array when el is element) result namespace: (root, namespace, routes) -> parts = namespace.split(".") return routes if parts.length == 0 for part, index in parts if index < parts.length - 1 root = (root[part] or= {}) else return root[part] = routes configure: (new_config) -> @configuration = @merge(@configuration, new_config) config: -> @clone(@configuration) make: -> routes = ROUTES routes.configure = (config) -> Utils.configure(config) routes.config = -> Utils.config() Object.defineProperty routes, 'defaults', get: -> throw new Error("#{NAMESPACE}.defaults is removed. Use #{NAMESPACE}.configure() instead.") set: (value) -> routes.default_serializer = (object, prefix) -> Utils.default_serializer(object, prefix) Utils.namespace(root, NAMESPACE, routes) # Set up Routes appropriately for the environment. if typeof define is "function" and define.amd # AMD define [], -> Utils.make() else # Browser globals Utils.make() ruby-js-routes-1.4.4/lib/tasks/000077500000000000000000000000001340547247200163355ustar00rootroot00000000000000ruby-js-routes-1.4.4/lib/tasks/js_routes.rake000066400000000000000000000003011340547247200212100ustar00rootroot00000000000000namespace :js do desc "Make a js file that will have functions that will return restful routes/urls." task routes: :environment do require "js-routes" JsRoutes.generate! end end ruby-js-routes-1.4.4/spec/000077500000000000000000000000001340547247200153745ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/dummy/000077500000000000000000000000001340547247200165275ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/dummy/app/000077500000000000000000000000001340547247200173075ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/dummy/app/assets/000077500000000000000000000000001340547247200206115ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/dummy/app/assets/javascripts/000077500000000000000000000000001340547247200231425ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/dummy/app/assets/javascripts/.gitkeep000066400000000000000000000000001340547247200245610ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/dummy/config/000077500000000000000000000000001340547247200177745ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/dummy/config/routes.rb000066400000000000000000000046351340547247200216520ustar00rootroot00000000000000App.routes.draw do resource "3df1b2d050ae5a96eac8565c9daef37a" resource "341f9e69e3db1c344de2fc6551885711" resource "0e1bcb2dc1ce4d80ec15cae9140fb99a" resource "15b91c612530bfc69c70d121c8713da4" resource "49e12936168a64dce4d4ec148104fb5a" resource "d878104611f88952aba49965c1d2d573" resource "0e94bfc3c8aaee5ea09579fe73cbdaff" resource "e1c2dd2ea9c63b380eb0947a0e1f49aa" resource "587c6e26ad7f9a6aa09f81add77b16f5" resource "8e00bfffebe0c874d6dad1c7b8c7cd6b" resource "394482d3515e7e49989a8496afa7d367" resource "4ab9c701622cba87eae50795564abe1c" resource "af4b4a2ea501fefbdb8367eb108b2e14" resource "116d17a93932a9a3e5bd2750665582f9" resource "315f0a62063288cd56373c8a00870596" resource "d5357ec6df4589f81ca8689cf0231667" resource "560a3b8cf807e873843cd889400cd52b" resource "361de6041f545e67db1aeaa6206c8ac7" resource "28b0a54de4a0884386f1e324edc13194" resource "ab77f21a956d956295187806cdf38cd1" resource "0b8a362fd486247fb7c41898709b9815" resource "5efa0a96733bc027b3309ffb54d1d1d0" resource "70a3ee535c59fcf59c58b6d39178833c" resource "5095fc05868c673ce450524f78cd28d3" resource "79b994cfbc79432d644a3b83804f4924" resource "e25125c477cd451fd74a76eaaebc9165" resource "672fbfb432687e2fee7d0e799cc10ea4" resource "2eb8350243305659082eb92b2e5b702c" resource "08c9973b624e10b10dc7235659c81346" resource "fee0d4b123529a2c652bef0ec0116ef2" resource "8422445d2aa176b7733473164c461a2e" resource "c24b8252b235431ca3df21a6ac119062" resource "c08c66c7fc40e9937ff84a86f6c6d18a" resource "964851acca72064d861188150e848d55" resource "d02927a4fd37b37c03dbad5d3c7a4753" resource "2a69df680ff9bd8d3855d9ce5a4e51f7" resource "d8daed677f9a9a6926005afbdeebcf73" resource "83d4db872f5f148e9ead108d483fec78" resource "09f9fb4250595d26f4149b76fcfa957d" resource "956cdb4d3cbf36bb9ccb7c7fcc36a602" resource "02816449a6c929f55f8bad958f25d25a" resource "2dd7ae38bd72f7e8b26aafb5f002d634" resource "c7c9aaa3f7131f1e7dbc9325b3426d3e" resource "7556e7d17c2a26acbad7d5fa86e6e640" resource "d03081ef427a227a808c708282fdc86b" resource "8f610d21e6e499c1eea98ca08191c05f" resource "b6b412ae8a369f6bfc7f312245eacc8c" resource "e9bcda8b00879c49bd7f05afee59a28e" resource "6e89f4baddd4044b42be7c2d3b382567" resource "5959c376d15a609f2e74f4f351d0a565" resource "3b7e418511c305c78f2d2c292a3a1289" resource "87acf6bf6e8191ff8900f420b33d5268" resource "648a9b17078423f29f42aa2ecac1cc7d" end ruby-js-routes-1.4.4/spec/js_routes/000077500000000000000000000000001340547247200174115ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/js_routes/amd_compatibility_spec.rb000066400000000000000000000023701340547247200244440ustar00rootroot00000000000000require "spec_helper" describe JsRoutes, "compatibility with AMD/require.js" do before(:each) do evaljs("window.GlobalCheck = {};") evaljs("window.define = function (requirs, callback) { window.GlobalCheck['js-routes'] = callback.call(this); return window.GlobalCheck['js-routes']; };") evaljs("window.define.amd = { jQuery: true };") strRequire =< name}) end after(:each) do FileUtils.rm_f(name) end after(:all) do FileUtils.rm_f("#{File.dirname(__FILE__)}/../routes.js") # let(:name) is not available here end it "should not generate file before initialization" do # This method is alread fixed in Rails master # But in 3.2 stable we need to hack it like this if Rails.application.instance_variable_get("@initialized") pending end expect(File.exists?(name)).to be_falsey end end describe "compiled javascript asset" do subject { ERB.new(File.read("app/assets/javascripts/js-routes.js.erb")).result(binding) } it "should have js routes code" do is_expected.to include("inbox_message_path: Utils.route([[\"inbox_id\",true],[\"id\",true],[\"format\",false]]") end end end ruby-js-routes-1.4.4/spec/js_routes/options_spec.rb000066400000000000000000000441721340547247200224530ustar00rootroot00000000000000require 'spec_helper' describe JsRoutes, "options" do before(:each) do evaljs(_presetup) if _presetup with_warnings(_warnings) do evaljs(JsRoutes.generate(_options)) end end let(:_presetup) { nil } let(:_options) { {} } let(:_warnings) { true } describe "serializer" do context "when specified" do # define custom serializer # this is a nonsense serializer, which always returns foo=bar # for all inputs let(:_presetup){ %q(function myCustomSerializer(object, prefix) { return "foo=bar"; }) } let(:_options) { {:serializer => "myCustomSerializer"} } it "should set configurable serializer" do # expect the nonsense serializer above to have appened foo=bar # to the end of the path expect(evaljs(%q(Routes.inboxes_path()))).to eql("/inboxes?foo=bar") end end context "when specified, but not function" do let(:_presetup){ %q(var myCustomSerializer = 1) } let(:_options) { {:serializer => "myCustomSerializer"} } it "should set configurable serializer" do # expect to use default expect(evaljs(%q(Routes.inboxes_path({a: 1})))).to eql("/inboxes?a=1") end end context "when configured in js" do let(:_options) { {:serializer =>%q(function (object, prefix) { return "foo=bar"; })} } it "uses JS serializer" do evaljs("Routes.configure({serializer: function (object, prefix) { return 'bar=baz'; }})") expect(evaljs(%q(Routes.inboxes_path({a: 1})))).to eql("/inboxes?bar=baz") end end end context "when exclude is specified" do let(:_options) { {:exclude => /^admin_/} } it "should exclude specified routes from file" do expect(evaljs("Routes.admin_users_path")).to be_nil end it "should not exclude routes not under specified pattern" do expect(evaljs("Routes.inboxes_path()")).not_to be_nil end context "for rails engine" do let(:_options) { {:exclude => /^blog_app_posts/} } it "should exclude specified engine route" do expect(evaljs("Routes.blog_app_posts_path")).to be_nil end end end context "when include is specified" do let(:_options) { {:include => /^admin_/} } it "should exclude specified routes from file" do expect(evaljs("Routes.admin_users_path()")).not_to be_nil end it "should not exclude routes not under specified pattern" do expect(evaljs("Routes.inboxes_path")).to be_nil end context "for rails engine" do let(:_options) { {:include => /^blog_app_posts/} } it "should include specified engine route" do expect(evaljs("Routes.blog_app_posts_path()")).not_to be_nil end end end context "when prefix with trailing slash is specified" do let(:_options) { {:prefix => "/myprefix/" } } it "should render routing with prefix" do expect(evaljs("Routes.inbox_path(1)")).to eq("/myprefix#{test_routes.inbox_path(1)}") end it "should render routing with prefix set in JavaScript" do evaljs("Routes.configure({prefix: '/newprefix/'})") expect(evaljs("Routes.config().prefix")).to eq("/newprefix/") expect(evaljs("Routes.inbox_path(1)")).to eq("/newprefix#{test_routes.inbox_path(1)}") end end context "when prefix with http:// is specified" do let(:_options) { {:prefix => "http://localhost:3000" } } it "should render routing with prefix" do expect(evaljs("Routes.inbox_path(1)")).to eq(_options[:prefix] + test_routes.inbox_path(1)) end end context "when prefix without trailing slash is specified" do let(:_options) { {:prefix => "/myprefix" } } it "should render routing with prefix" do expect(evaljs("Routes.inbox_path(1)")).to eq("/myprefix#{test_routes.inbox_path(1)}") end it "should render routing with prefix set in JavaScript" do evaljs("Routes.configure({prefix: '/newprefix/'})") expect(evaljs("Routes.inbox_path(1)")).to eq("/newprefix#{test_routes.inbox_path(1)}") end end context "when default format is specified" do let(:_options) { {:default_url_options => {format: "json"}} } let(:_warnings) { nil } it "should render routing with default_format" do expect(evaljs("Routes.inbox_path(1)")).to eq(test_routes.inbox_path(1, :format => "json")) end it "should render routing with default_format and zero object" do expect(evaljs("Routes.inbox_path(0)")).to eq(test_routes.inbox_path(0, :format => "json")) end it "should override default_format when spefified implicitly" do expect(evaljs("Routes.inbox_path(1, {format: 'xml'})")).to eq(test_routes.inbox_path(1, :format => "xml")) end it "should override nullify implicitly when specified implicitly" do expect(evaljs("Routes.inbox_path(1, {format: null})")).to eq(test_routes.inbox_path(1)) end it "shouldn't require the format" do pending if Rails.version < "4.0" expect(evaljs("Routes.json_only_path()")).to eq(test_routes.json_only_path(:format => 'json')) end end it "shouldn't include the format when {:format => false} is specified" do expect(evaljs("Routes.no_format_path()")).to eq(test_routes.no_format_path()) expect(evaljs("Routes.no_format_path({format: 'json'})")).to eq(test_routes.no_format_path(format: 'json')) end describe "when namespace option is specified" do let(:_options) { {:namespace => "PHM"} } it "should use this namespace for routing" do expect(evaljs("window.Routes")).to be_nil expect(evaljs("PHM.inbox_path")).not_to be_nil end end describe "when nested namespace option is specified" do context "and defined on client" do let(:_presetup) { "window.PHM = {}" } let(:_options) { {:namespace => "PHM.Routes"} } it "should use this namespace for routing" do expect(evaljs("PHM.Routes.inbox_path")).not_to be_nil end end context "but undefined on client" do let(:_options) { {:namespace => "PHM.Routes"} } it "should initialize namespace" do expect(evaljs("window.PHM.Routes.inbox_path")).not_to be_nil end end context "and some parts are defined" do let(:_presetup) { "window.PHM = { Utils: {} };" } let(:_options) { {:namespace => "PHM.Routes"} } it "should not overwrite existing parts" do expect(evaljs("window.PHM.Utils")).not_to be_nil expect(evaljs("window.PHM.Routes.inbox_path")).not_to be_nil end end end describe "default_url_options" do context "with optional route parts" do context "provided" do let(:_options) { { :default_url_options => { :optional_id => "12", :format => "json" } } } it "should use this opions to fill optional parameters" do expect(evaljs("Routes.things_path()")).to eq(test_routes.things_path(:optional_id => 12, :format => "json")) end end context "not provided" do let(:_options) { { :default_url_options => { :format => "json" } } } it "breaks" do expect(evaljs("Routes.foo_all_path()")).to eq(test_routes.foo_all_path(:format => "json")) end end end context "with required route parts" do let(:_options) { {:default_url_options => {:inbox_id => "12"}} } it "should use this opions to fill optional parameters" do expect(evaljs("Routes.inbox_messages_path()")).to eq(test_routes.inbox_messages_path(:inbox_id => 12)) end end context "when overwritten on JS level" do let(:_options) { { :default_url_options => { :format => "json" } } } it "uses JS defined value" do evaljs("Routes.configure({default_url_options: {format: 'xml'}})") expect(evaljs("Routes.inboxes_path()")).to eq(test_routes.inboxes_path(format: 'xml')) end end end describe "trailing_slash" do context "with default option" do let(:_options) { Hash.new } it "should working in params" do expect(evaljs("Routes.inbox_path(1, {trailing_slash: true})")).to eq(test_routes.inbox_path(1, :trailing_slash => true)) end it "should working with additional params" do expect(evaljs("Routes.inbox_path(1, {trailing_slash: true, test: 'params'})")).to eq(test_routes.inbox_path(1, :trailing_slash => true, :test => 'params')) end end context "with default_url_options option" do let(:_options) { {:default_url_options => {:trailing_slash => true}} } it "should working" do expect(evaljs("Routes.inbox_path(1, {test: 'params'})")).to eq(test_routes.inbox_path(1, :trailing_slash => true, :test => 'params')) end it "should remove it by params" do expect(evaljs("Routes.inbox_path(1, {trailing_slash: false})")).to eq(test_routes.inbox_path(1)) end end context "with disabled default_url_options option" do let(:_options) { {:default_url_options => {:trailing_slash => false}} } it "should not use trailing_slash" do expect(evaljs("Routes.inbox_path(1, {test: 'params'})")).to eq(test_routes.inbox_path(1, :test => 'params')) end it "should use it by params" do expect(evaljs("Routes.inbox_path(1, {trailing_slash: true})")).to eq(test_routes.inbox_path(1, :trailing_slash => true)) end end end describe "camel_case" do context "with default option" do let(:_options) { Hash.new } it "should use snake case routes" do expect(evaljs("Routes.inbox_path(1)")).to eq(test_routes.inbox_path(1)) expect(evaljs("Routes.inboxPath")).to be_nil end end context "with true" do let(:_options) { { :camel_case => true } } it "should generate camel case routes" do expect(evaljs("Routes.inbox_path")).to be_nil expect(evaljs("Routes.inboxPath")).not_to be_nil expect(evaljs("Routes.inboxPath(1)")).to eq(test_routes.inbox_path(1)) expect(evaljs("Routes.inboxMessagesPath(10)")).to eq(test_routes.inbox_messages_path(:inbox_id => 10)) end end end describe "url_links" do context "with default option" do let(:_options) { Hash.new } it "should generate only path links" do expect(evaljs("Routes.inbox_path(1)")).to eq(test_routes.inbox_path(1)) expect(evaljs("Routes.inbox_url")).to be_nil end end context "when configuring with default_url_options" do context "when only host option is specified" do let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com"} } } it "uses the specified host, defaults protocol to http, defaults port to 80 (leaving it blank)" do expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com#{test_routes.inbox_path(1)}") end it "does not override protocol when specified in route" do expect(evaljs("Routes.new_session_url()")).to eq("https://example.com#{test_routes.new_session_path}") end it "does not override host when specified in route" do expect(evaljs("Routes.sso_url()")).to eq(test_routes.sso_url) end it "does not override port when specified in route" do expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080#{test_routes.portals_path}") end end context "when default host and protocol are specified" do let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com", :protocol => "ftp"} } } it "uses the specified protocol and host, defaults port to 80 (leaving it blank)" do expect(evaljs("Routes.inbox_url(1)")).to eq("ftp://example.com#{test_routes.inbox_path(1)}") end it "does not override protocol when specified in route" do expect(evaljs("Routes.new_session_url()")).to eq("https://example.com#{test_routes.new_session_path}") end it "does not override host when host is specified in route" do expect(evaljs("Routes.sso_url()")).to eq("ftp://sso.example.com#{test_routes.sso_path}") end it "does not override port when specified in route" do expect(evaljs("Routes.portals_url()")).to eq("ftp://example.com:8080#{test_routes.portals_path}") end end context "when default host and port are specified" do let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com", :port => 3000} } } it "uses the specified host and port, defaults protocol to http" do expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com:3000#{test_routes.inbox_path(1)}") end it "does not override protocol when specified in route" do expect(evaljs("Routes.new_session_url()")).to eq("https://example.com:3000#{test_routes.new_session_path}") end it "does not override host, protocol, or port when host is specified in route" do expect(evaljs("Routes.sso_url()")).to eq("http://sso.example.com:3000" + test_routes.sso_path) end it "does not override parts when specified in route" do expect(evaljs("Routes.secret_root_url()")).to eq(test_routes.secret_root_url) end end context "with camel_case option" do let(:_options) { { :camel_case => true, :url_links => true, :default_url_options => {:host => "example.com"} } } it "should generate path and url links" do expect(evaljs("Routes.inboxUrl(1)")).to eq("http://example.com#{test_routes.inbox_path(1)}") end end context "with prefix option" do let(:_options) { { :prefix => "/api", :url_links => true, :default_url_options => {:host => 'example.com'} } } it "should generate path and url links" do expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com/api#{test_routes.inbox_path(1)}") end end context "with compact option" do let(:_options) { { :compact => true, :url_links => true, :default_url_options => {:host => 'example.com'} } } it "does not affect url helpers" do expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com#{test_routes.inbox_path(1)}") end end end context 'when window.location is present' do let(:current_protocol) { 'http:' } # window.location.protocol includes the colon character let(:current_hostname) { 'current.example.com' } let(:current_port){ '' } # an empty string means port 80 let(:current_host) do host = "#{current_hostname}" host += ":#{current_port}" unless current_port == '' host end before do jscontext.eval("window = {'location': {'protocol': '#{current_protocol}', 'hostname': '#{current_hostname}', 'port': '#{current_port}', 'host': '#{current_host}'}}") end context "without specifying a default host" do let(:_options) { { :url_links => true } } it "uses the current host" do expect(evaljs("Routes.inbox_path")).not_to be_nil expect(evaljs("Routes.inbox_url")).not_to be_nil expect(evaljs("Routes.inbox_url(1)")).to eq("http://current.example.com#{test_routes.inbox_path(1)}") expect(evaljs("Routes.inbox_url(1, { test_key: \"test_val\" })")).to eq("http://current.example.com#{test_routes.inbox_path(1, :test_key => "test_val")}") expect(evaljs("Routes.new_session_url()")).to eq("https://current.example.com#{test_routes.new_session_path}") end it "doesn't use current when specified in the route" do expect(evaljs("Routes.sso_url()")).to eq(test_routes.sso_url) end it "uses host option as an argument" do expect(evaljs("Routes.secret_root_url({host: 'another.com'})")).to eq(test_routes.secret_root_url(host: 'another.com')) end it "uses port option as an argument" do expect(evaljs("Routes.secret_root_url({host: 'localhost', port: 8080})")).to eq(test_routes.secret_root_url(host: 'localhost', port: 8080)) end it "uses protocol option as an argument" do expect(evaljs("Routes.secret_root_url({host: 'localhost', protocol: 'https'})")).to eq(test_routes.secret_root_url(protocol: 'https', host: 'localhost')) end it "uses subdomain option as an argument" do expect(evaljs("Routes.secret_root_url({subdomain: 'custom'})")).to eq(test_routes.secret_root_url(subdomain: 'custom')) end end end context 'when window.location is not present' do context 'without specifying a default host' do let(:_options) { { url_links: true } } it 'generates path' do expect(evaljs("Routes.inbox_url(1)")).to eq test_routes.inbox_path(1) expect(evaljs("Routes.new_session_url()")).to eq test_routes.new_session_path end end end end describe "when the compact mode is enabled" do let(:_options) { { :compact => true } } it "removes _path suffix from path helpers" do expect(evaljs("Routes.inbox_path")).to be_nil expect(evaljs("Routes.inboxes()")).to eq(test_routes.inboxes_path()) expect(evaljs("Routes.inbox(2)")).to eq(test_routes.inbox_path(2)) end context "with url_links option" do around(:each) do |example| ActiveSupport::Deprecation.silence do example.run end end let(:_options) { { :compact => true, :url_links => true, default_url_options: {host: 'localhost'} } } it "should not strip urls" do expect(evaljs("Routes.inbox(1)")).to eq(test_routes.inbox_path(1)) expect(evaljs("Routes.inbox_url(1)")).to eq("http://localhost#{test_routes.inbox_path(1)}") end end end describe "special_options_key" do let(:_options) { { special_options_key: :__options__ } } it "can be redefined" do expect { expect(evaljs("Routes.inbox_message_path({inbox_id: 1, id: 2, _options: true})")).to eq("") }.to raise_error(js_error_class) expect(evaljs("Routes.inbox_message_path({inbox_id: 1, id: 2, __options__: true})")).to eq(test_routes.inbox_message_path(inbox_id: 1, id: 2)) end end describe "when application is specified" do let(:_options) { {:application => BlogEngine::Engine} } it "should include specified engine route" do expect(evaljs("Routes.posts_path()")).not_to be_nil end end end ruby-js-routes-1.4.4/spec/js_routes/rails_routes_compatibility_spec.rb000066400000000000000000000452151340547247200264230ustar00rootroot00000000000000require "spec_helper" describe JsRoutes, "compatibility with Rails" do before(:each) do evaljs(JsRoutes.generate({})) end it "should generate collection routing" do expect(evaljs("Routes.inboxes_path()")).to eq(test_routes.inboxes_path()) end it "should generate member routing" do expect(evaljs("Routes.inbox_path(1)")).to eq(test_routes.inbox_path(1)) end it "should raise error if required argument is not passed" do expect { evaljs("Routes.thing_path()") } .to raise_error('Route parameter missing: id') expect { evaljs("Routes.search_path()") } .to raise_error('Route parameter missing: q') expect { evaljs("Routes.book_path()") } .to raise_error('Route parameter missing: title') expect { evaljs("Routes.book_title_path()") } .to raise_error('Route parameter missing: title') end it "should produce error stacktraces including function names" do stacktrace = evaljs(" (function(){ try { Routes.thing_path() } catch(e) { return e.stack; } })() ") expect(stacktrace).to include "thing_path" end it "should support 0 as a member parameter" do expect(evaljs("Routes.inbox_path(0)")).to eq(test_routes.inbox_path(0)) end it "should generate nested routing with one parameter" do expect(evaljs("Routes.inbox_messages_path(1)")).to eq(test_routes.inbox_messages_path(1)) end it "should generate nested routing" do expect(evaljs("Routes.inbox_message_path(1,2)")).to eq(test_routes.inbox_message_path(1, 2)) end it "should generate routing with format" do expect(evaljs("Routes.inbox_path(1, {format: 'json'})")).to eq(test_routes.inbox_path(1, :format => "json")) end it "should support routes with reserved javascript words as parameters" do expect(evaljs("Routes.object_path(1, 2)")).to eq(test_routes.object_path(1,2)) end it "should support routes with trailing_slash" do expect(evaljs("Routes.inbox_path(1, {trailing_slash: true})")).to eq(test_routes.inbox_path(1, trailing_slash: true)) end it "should support url anchor given as parameter" do expect(evaljs("Routes.inbox_path(1, {anchor: 'hello'})")).to eq(test_routes.inbox_path(1, :anchor => "hello")) end it "should support url anchor and get parameters" do expect(evaljs("Routes.inbox_path(1, {expanded: true, anchor: 'hello'})")).to eq(test_routes.inbox_path(1, :expanded => true, :anchor => "hello")) end it "should use irregular ActiveSupport pluralizations" do expect(evaljs("Routes.budgies_path()")).to eq(test_routes.budgies_path) expect(evaljs("Routes.budgie_path(1)")).to eq(test_routes.budgie_path(1)) expect(evaljs("Routes.budgy_path")).to eq(nil) expect(evaljs("Routes.budgie_descendents_path(1)")).to eq(test_routes.budgie_descendents_path(1)) end describe "when route has defaults" do it "should support route default format" do expect(evaljs("Routes.api_purchases_path()")).to eq(test_routes.api_purchases_path) end it 'should support route default subdomain' do expect(evaljs("Routes.backend_root_path()")).to eq(test_routes.backend_root_path) end it "should support default format override" do expect(evaljs("Routes.api_purchases_path({format: 'xml'})")).to eq(test_routes.api_purchases_path(format: 'xml')) end it "should support default format override by passing it in args" do expect(evaljs("Routes.api_purchases_path('xml')")).to eq(test_routes.api_purchases_path('xml')) end it "doesn't apply defaults to path" do expect(evaljs("Routes.with_defaults_path()")).to eq(test_routes.with_defaults_path) end end context "with rails engines" do it "should support simple route" do expect(evaljs("Routes.blog_app_posts_path()")).to eq(blog_routes.posts_path()) end it "should support root route" do expect(evaljs("Routes.blog_app_path()")).to eq(test_routes.blog_app_path()) end it "should support route with parameters" do expect(evaljs("Routes.blog_app_post_path(1)")).to eq(blog_routes.post_path(1)) end it "should support root path" do expect(evaljs("Routes.blog_app_root_path()")).to eq(blog_routes.root_path) end it "should support single route mapping" do expect(evaljs("Routes.support_path({page: 3})")).to eq(test_routes.support_path(:page => 3)) end end it "shouldn't require the format" do expect(evaljs("Routes.json_only_path({format: 'json'})")).to eq(test_routes.json_only_path(:format => 'json')) end it "should serialize object with empty string value" do expect(evaljs("Routes.inboxes_path({a: '', b: 1})")).to eq(test_routes.inboxes_path(:a => '', :b => 1)) end it "should support utf-8 route" do expect(evaljs("Routes.hello_path()")).to eq(test_routes.hello_path) end it "should support root_path" do expect(evaljs("Routes.root_path()")).to eq(test_routes.root_path) end describe "get paramters" do it "should support simple get parameters" do expect(evaljs("Routes.inbox_path(1, {format: 'json', lang: 'ua', q: 'hello'})")).to eq(test_routes.inbox_path(1, :lang => "ua", :q => "hello", :format => "json")) end it "should support array get parameters" do expect(evaljs("Routes.inbox_path(1, {hello: ['world', 'mars']})")).to eq(test_routes.inbox_path(1, :hello => [:world, :mars])) end it "should support nested get parameters" do expect(evaljs("Routes.inbox_path(1, {format: 'json', env: 'test', search: { category_ids: [2,5], q: 'hello'}})")).to eq( test_routes.inbox_path(1, :env => 'test', :search => {:category_ids => [2,5], :q => "hello"}, :format => "json") ) end it "should support null and undefined parameters" do expect(evaljs("Routes.inboxes_path({uri: null, key: undefined})")).to eq(test_routes.inboxes_path(:uri => nil, :key => nil)) end it "should escape get parameters" do expect(evaljs("Routes.inboxes_path({uri: 'http://example.com'})")).to eq(test_routes.inboxes_path(:uri => 'http://example.com')) end end context "routes globbing" do it "should be supported as parameters" do expect(evaljs("Routes.book_path('thrillers', 1)")).to eq(test_routes.book_path('thrillers', 1)) end it "should support routes globbing as array" do expect(evaljs("Routes.book_path(['thrillers'], 1)")).to eq(test_routes.book_path(['thrillers'], 1)) end it "should bee support routes globbing as array" do expect(evaljs("Routes.book_path([1, 2, 3], 1)")).to eq(test_routes.book_path([1, 2, 3], 1)) end it "should bee support routes globbing as hash" do expect(evaljs("Routes.book_path('a_test/b_test/c_test', 1)")).to eq(test_routes.book_path('a_test/b_test/c_test', 1)) end it "should support routes globbing as array with optional params" do expect(evaljs("Routes.book_path([1, 2, 3, 5], 1, {c: '1'})")).to eq(test_routes.book_path([1, 2, 3, 5], 1, { :c => "1" })) end it "should support routes globbing in book_title route as array" do expect(evaljs("Routes.book_title_path('john', ['thrillers', 'comedian'])")).to eq(test_routes.book_title_path('john', ['thrillers', 'comedian'])) end it "should support routes globbing in book_title route as array with optional params" do expect(evaljs("Routes.book_title_path('john', ['thrillers', 'comedian'], {some_key: 'some_value'})")).to eq(test_routes.book_title_path('john', ['thrillers', 'comedian'], {:some_key => 'some_value'})) end it "should support required paramters given as options hash" do expect(evaljs("Routes.search_path({q: 'hello'})")).to eq(test_routes.search_path(:q => 'hello')) end it "should support nested object null parameters" do expect(evaljs("Routes.inboxes_path({hello: {world: null}})")).to eq(test_routes.inboxes_path(:hello => {:world => nil})) end end context "using optional path fragments" do context "including not optional parts" do it "should include everything that is not optional" do expect(evaljs("Routes.foo_path()")).to eq(test_routes.foo_path) end end context "but not including them" do it "should not include the optional parts" do expect(evaljs("Routes.things_path()")).to eq(test_routes.things_path) expect(evaljs("Routes.things_path({ q: 'hello' })")).to eq(test_routes.things_path(q: 'hello')) end it "should not require the optional parts as arguments" do expect(evaljs("Routes.thing_path(null, 5)")).to eq(test_routes.thing_path(nil, 5)) end it "should treat undefined as non-given optional part" do expect(evaljs("Routes.thing_path(5, {optional_id: undefined})")).to eq(test_routes.thing_path(5, :optional_id => nil)) end it "should raise error when passing non-full list of arguments and some query params" do expect { evaljs("Routes.thing_path(5, {q: 'hello'})") } .to raise_error('Route parameter missing: id') end it "should treat null as non-given optional part" do expect(evaljs("Routes.thing_path(5, {optional_id: null})")).to eq(test_routes.thing_path(5, :optional_id => nil)) end it "should work when passing required params in options" do expect(evaljs("Routes.thing_deep_path({second_required: 1, third_required: 2})")).to eq(test_routes.thing_deep_path(second_required: 1, third_required: 2)) end it "should skip leading and trailing optional parts" do skip if Rails.version < '4' expect(evaljs("Routes.thing_deep_path(1, 2)")).to eq(test_routes.thing_deep_path(1, 2)) end end context "and including them" do if Rails.version < '4' it "should fail when insufficient arguments are given" do expect { evaljs("Routes.thing_deep_path(1)")} .to raise_error('Route parameter missing: second_required') expect { evaljs("Routes.thing_deep_path(1,2)")} .to raise_error('Route parameter missing: third_required') end end it "should include the optional parts" do expect(evaljs("Routes.things_path({optional_id: 5})")).to eq(test_routes.things_path(:optional_id => 5)) expect(evaljs("Routes.things_path(5)")).to eq(test_routes.things_path(5)) expect(evaljs("Routes.thing_deep_path(1, { third_required: 3, second_required: 2 })")).to eq(test_routes.thing_deep_path(1, third_required: 3, second_required: 2)) expect(evaljs("Routes.thing_deep_path(1, { third_required: 3, second_required: 2, forth_optional: 4 })")).to eq(test_routes.thing_deep_path(1, third_required: 3, second_required: 2, forth_optional: 4)) expect(evaljs("Routes.thing_deep_path(2, { third_required: 3, first_optional: 1 })")).to eq(test_routes.thing_deep_path(2, third_required: 3, first_optional: 1)) expect(evaljs("Routes.thing_deep_path(3, { first_optional: 1, second_required: 2 })")).to eq(test_routes.thing_deep_path(3, first_optional: 1, second_required: 2)) expect(evaljs("Routes.thing_deep_path(3, { first_optional: 1, second_required: 2, forth_optional: 4 })")).to eq(test_routes.thing_deep_path(3, first_optional: 1, second_required: 2, forth_optional: 4)) expect(evaljs("Routes.thing_deep_path(4, { first_optional: 1, second_required: 2, third_required: 3 })")).to eq(test_routes.thing_deep_path(4, first_optional: 1, second_required: 2, third_required: 3)) expect(evaljs("Routes.thing_deep_path(1, 2, { third_required: 3 })")).to eq(test_routes.thing_deep_path(1, 2, third_required: 3)) expect(evaljs("Routes.thing_deep_path(1,2, {third_required: 3, q: 'bogdan'})")).to eq(test_routes.thing_deep_path(1,2, {third_required: 3, q: 'bogdan'})) expect(evaljs("Routes.thing_deep_path(1, 2, { forth_optional: 4, third_required: 3 })")).to eq(test_routes.thing_deep_path(1, 2, forth_optional: 4, third_required: 3)) expect(evaljs("Routes.thing_deep_path(1, 3, { second_required: 2 })")).to eq(test_routes.thing_deep_path(1, 3, second_required: 2)) expect(evaljs("Routes.thing_deep_path(1, 4, { second_required: 2, third_required: 3 })")).to eq(test_routes.thing_deep_path(1, 4, second_required: 2, third_required: 3)) expect(evaljs("Routes.thing_deep_path(2, 3, { first_optional: 1 })")).to eq(test_routes.thing_deep_path(2, 3, first_optional: 1)) expect(evaljs("Routes.thing_deep_path(2, 3, { first_optional: 1, forth_optional: 4 })")).to eq(test_routes.thing_deep_path(2, 3, first_optional: 1, forth_optional: 4)) expect(evaljs("Routes.thing_deep_path(2, 4, { first_optional: 1, third_required: 3 })")).to eq(test_routes.thing_deep_path(2, 4, first_optional: 1, third_required: 3)) expect(evaljs("Routes.thing_deep_path(3, 4, { first_optional: 1, second_required: 2 })")).to eq(test_routes.thing_deep_path(3, 4, first_optional: 1, second_required: 2)) expect(evaljs("Routes.thing_deep_path(1, 2, 3)")).to eq(test_routes.thing_deep_path(1, 2, 3)) expect(evaljs("Routes.thing_deep_path(1, 2, 3, { forth_optional: 4 })")).to eq(test_routes.thing_deep_path(1, 2, 3, forth_optional: 4)) expect(evaljs("Routes.thing_deep_path(1, 2, 4, { third_required: 3 })")).to eq(test_routes.thing_deep_path(1, 2, 4, third_required: 3)) expect(evaljs("Routes.thing_deep_path(1, 3, 4, { second_required: 2 })")).to eq(test_routes.thing_deep_path(1, 3, 4, second_required: 2)) expect(evaljs("Routes.thing_deep_path(2, 3, 4, { first_optional: 1 })")).to eq(test_routes.thing_deep_path(2, 3, 4, first_optional: 1)) expect(evaljs("Routes.thing_deep_path(1, 2, 3, 4)")).to eq(test_routes.thing_deep_path(1, 2, 3, 4)) end context "on nested optional parts" do if Rails.version <= "5.0.0" # this type of routing is deprecated it "should include everything that is not optional" do expect(evaljs("Routes.classic_path({controller: 'classic', action: 'edit'})")).to eq(test_routes.classic_path(controller: :classic, action: :edit)) end end end end end context "when wrong parameters given" do it "should throw Exception if not enough parameters" do expect { evaljs("Routes.inbox_path()") }.to raise_error(js_error_class) end it "should throw Exception if required parameter is not defined" do expect { evaljs("Routes.inbox_path(null)") }.to raise_error(js_error_class) end it "should throw Exceptions if when there is too many parameters" do expect { evaljs("Routes.inbox_path(1,2,3)") }.to raise_error(js_error_class) end it "should throw Exceptions if when pass id with null" do expect { evaljs("Routes.inbox_path({id: null})") }.to raise_error(js_error_class) end it "should throw Exceptions if when pass to_param with null" do expect { evaljs("Routes.inbox_path({to_param: null})") }.to raise_error(js_error_class) end end context "when javascript engine without Array#indexOf is used" do before(:each) do evaljs("Array.prototype.indexOf = null") end it "should still work correctly" do expect(evaljs("Routes.inboxes_path()")).to eq(test_routes.inboxes_path()) end end context "when arguments are objects" do let(:klass) { Struct.new(:id, :to_param) } let(:inbox) { klass.new(1,"my") } it "should support 0 as a to_param option" do expect(evaljs("Routes.inbox_path({to_param: 0})")).to eq(test_routes.inbox_path(0)) end it "should check for options special key" do expect(evaljs("Routes.inbox_path({id: 7, q: 'hello', _options: true})")).to eq(test_routes.inbox_path(id: 7, q: 'hello')) expect { evaljs("Routes.inbox_path({to_param: 7, _options: true})") }.to raise_error(js_error_class) expect(evaljs("Routes.inbox_message_path(5, {id: 7, q: 'hello', _options: true})")).to eq(test_routes.inbox_message_path(5, id: 7, q: 'hello')) end it "should support 0 as an id option" do expect(evaljs("Routes.inbox_path({id: 0})")).to eq(test_routes.inbox_path(0)) end it "should use id property of the object in path" do expect(evaljs("Routes.inbox_path({id: 1})")).to eq(test_routes.inbox_path(1)) end it "should prefer to_param property over id property" do expect(evaljs("Routes.inbox_path({id: 1, to_param: 'my'})")).to eq(test_routes.inbox_path(inbox)) end it "should call to_param if it is a function" do expect(evaljs("Routes.inbox_path({id: 1, to_param: function(){ return 'my';}})")).to eq(test_routes.inbox_path(inbox)) end it "should call id if it is a function" do expect(evaljs("Routes.inbox_path({id: function() { return 1;}})")).to eq(test_routes.inbox_path(1)) end it "should support options argument" do expect(evaljs( "Routes.inbox_message_path({id:1, to_param: 'my'}, {id:2}, {custom: true, format: 'json'})" )).to eq(test_routes.inbox_message_path(inbox, 2, :custom => true, :format => "json")) end context "when globbing" do it "should prefer to_param property over id property" do expect(evaljs("Routes.book_path({id: 1, to_param: 'my'}, 1)")).to eq(test_routes.book_path(inbox, 1)) end it "should call to_param if it is a function" do expect(evaljs("Routes.book_path({id: 1, to_param: function(){ return 'my';}}, 1)")).to eq(test_routes.book_path(inbox, 1)) end it "should call id if it is a function" do expect(evaljs("Routes.book_path({id: function() { return 'technical';}}, 1)")).to eq(test_routes.book_path('technical', 1)) end it "should support options argument" do expect(evaljs( "Routes.book_path({id:1, to_param: 'my'}, {id:2}, {custom: true, format: 'json'})" )).to eq(test_routes.book_path(inbox, 2, :custom => true, :format => "json")) end end end context "when specs" do it "should show inbox spec" do expect(evaljs("Routes.inbox_path.toString()")).to eq('/inboxes/:id(.:format)') end it "should show inbox spec convert to string" do expect(evaljs("'' + Routes.inbox_path")).to eq('/inboxes/:id(.:format)') end it "should show inbox message spec" do expect(evaljs("Routes.inbox_message_path.toString()")).to eq('/inboxes/:inbox_id/messages/:id(.:format)') end it "should show inbox message spec convert to string" do expect(evaljs("'' + Routes.inbox_message_path")).to eq('/inboxes/:inbox_id/messages/:id(.:format)') end end describe "required_params" do it "should show inbox spec" do expect(evaljs("Routes.inbox_path.required_params").to_a).to eq(["id"]) end it "should show inbox message spec" do expect(evaljs("Routes.inbox_message_path.required_params").to_a).to eq(["inbox_id", "id"]) end end end ruby-js-routes-1.4.4/spec/js_routes/zzz_last_post_rails_init_spec.rb000066400000000000000000000070621340547247200261170ustar00rootroot00000000000000# we need to run post_rails_init_spec as the latest # because it cause unrevertable changes to runtime # what is why I added "zzz_last" in the beginning require 'spec_helper' require "fileutils" describe "after Rails initialization" do NAME = Rails.root.join('app', 'assets', 'javascripts', 'routes.js').to_s def sprockets_v3? Sprockets::VERSION.to_i >= 3 end def sprockets_context(environment, name, filename) if sprockets_v3? Sprockets::Context.new(environment: environment, name: name, filename: filename.to_s, metadata: {}) else Sprockets::Context.new(environment, name, filename) end end def evaluate(ctx, file) if sprockets_v3? ctx.load(ctx.environment.find_asset(file, pipeline: :default).uri).to_s else ctx.evaluate(file) end end before(:each) do FileUtils.rm_rf Rails.root.join('tmp/cache') FileUtils.rm_f NAME JsRoutes.generate!(NAME) end before(:all) do Rails.configuration.eager_load = false Rails.application.initialize! end it "should generate routes file" do expect(File.exists?(NAME)).to be_truthy end context "JsRoutes::Engine" do TEST_ASSET_PATH = Rails.root.join('app','assets','javascripts','test.js') before(:all) do File.open(TEST_ASSET_PATH,'w') do |f| f.puts "function() {}" end end after(:all) do FileUtils.rm_f(TEST_ASSET_PATH) end context "the preprocessor" do before(:each) do path = Rails.root.join('config','routes.rb').to_s if sprockets_v3? expect_any_instance_of(Sprockets::Context).to receive(:depend_on).with(path) else expect(ctx).to receive(:depend_on).with(path) end end let!(:ctx) do sprockets_context(Rails.application.assets, 'js-routes.js', Pathname.new('js-routes.js')) end context "when dealing with js-routes.js" do context "with Rails" do context "and initialize on precompile" do before(:each) do Rails.application.config.assets.initialize_on_precompile = true end it "should render some javascript" do expect(evaluate(ctx, 'js-routes.js')).to match(/routes = /) end end context "and not initialize on precompile" do before(:each) do Rails.application.config.assets.initialize_on_precompile = false end it "should raise an exception if 3 version" do if 3 == Rails::VERSION::MAJOR expect { evaluate(ctx, 'js-routes.js') }.to raise_error(/Cannot precompile/) else expect(evaluate(ctx, 'js-routes.js')).to match(/routes = /) end end end end end end context "when not dealing with js-routes.js" do it "should not depend on routes.rb" do ctx = sprockets_context(Rails.application.assets, 'test.js', TEST_ASSET_PATH) expect(ctx).not_to receive(:depend_on) evaluate(ctx, 'test.js') end end end end describe "JSRoutes thread safety" do before do begin Rails.application.initialize! rescue end end it "can produce the routes from multiple threads" do threads = 2.times.map do Thread.start do 10.times { expect { JsRoutes.generate }.to_not raise_error } end end threads.each do |thread| thread.join end end end ruby-js-routes-1.4.4/spec/spec_helper.rb000066400000000000000000000051661340547247200202220ustar00rootroot00000000000000# encoding: utf-8 $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $:.unshift(File.dirname(__FILE__)) require 'rspec' require 'rails/all' require 'js-routes' require 'active_support/core_ext/hash/slice' require 'coffee-script' # fix ends_with? error for rails 3.2 require 'active_support/core_ext/string/starts_ends_with' if 3 == Rails::VERSION::MAJOR if defined?(JRUBY_VERSION) require 'rhino' JS_LIB_CLASS = Rhino else require 'v8' JS_LIB_CLASS = V8 end def jscontext(force = false) if force @jscontext = JS_LIB_CLASS::Context.new else @jscontext ||= JS_LIB_CLASS::Context.new end end def js_error_class JS_LIB_CLASS::JSError end def evaljs(string, force = false) jscontext(force).eval(string) end def test_routes ::App.routes.url_helpers end def blog_routes BlogEngine::Engine.routes.url_helpers end ActiveSupport::Inflector.inflections do |inflect| inflect.irregular "budgie", "budgies" end module BlogEngine class Engine < Rails::Engine isolate_namespace BlogEngine end end class ::App < Rails::Application # Enable the asset pipeline config.assets.enabled = true # initialize_on_precompile config.assets.initialize_on_precompile = true if 3 == Rails::VERSION::MAJOR config.paths['config/routes'] << 'spec/config/routes.rb' else config.paths['config/routes.rb'] << 'spec/config/routes.rb' end config.root = File.expand_path('../dummy', __FILE__) end # prevent warning Rails.configuration.active_support.deprecation = :log # Requires supporting files with custom matchers and macros, etc, # in ./support/ and its subdirectories. Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = :expect end config.before(:all) do # compile all js files begin Dir["#{File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))}/**/*.coffee"].each do |coffee| File.open(coffee.gsub(/\.coffee$/, ""), 'w') do |f| f.write(CoffeeScript.compile(File.read(coffee)).lstrip) end end # compile all js files end draw_routes end config.before :each do evaljs("var window = this;", true) def inspectify(value) case value when V8::Array value.map do |v| inspectify(v) end when V8::Object value.to_h.map do |k,v| [k, inspectify(v)] end.to_h when String, nil, Integer, FalseClass, TrueClass value else raise "wtf #{value.class}?" end end jscontext[:log] = lambda do |context, value| puts inspectify(value).to_json end end end ruby-js-routes-1.4.4/spec/support/000077500000000000000000000000001340547247200171105ustar00rootroot00000000000000ruby-js-routes-1.4.4/spec/support/routes.rb000066400000000000000000000043241340547247200207610ustar00rootroot00000000000000def draw_routes BlogEngine::Engine.routes.draw do root to: "application#index" resources :posts end App.routes.draw do get 'support(/page/:page)', to: BlogEngine::Engine, as: 'support' resources :inboxes, only: [:index, :show] do resources :messages, only: [:index, :show] do resources :attachments, only: [:new, :show] end end root :to => "inboxes#index" namespace :admin do resources :users, only: [:index] end scope "/returns/:return" do resources :objects, only: [:show] end scope "(/optional/:optional_id)" do resources :things, only: [:show, :index] end get "(/sep1/:first_optional)/sep2/:second_required/sep3/:third_required(/:forth_optional)", as: :thing_deep, controller: :things, action: :show if Rails.version < "5.0.0" get "/:controller(/:action(/:id))" => "classic#classic", :as => :classic end get "/other_optional/(:optional_id)" => "foo#foo", :as => :foo get '/other_optional(/*optional_id)' => 'foo#foo', :as => :foo_all get 'books/*section/:title' => 'books#show', :as => :book get 'books/:title/*section' => 'books#show', :as => :book_title mount BlogEngine::Engine => "/blog", :as => :blog_app get '/no_format' => "foo#foo", :format => false, :as => :no_format get '/json_only' => "foo#foo", :format => true, :constraints => {:format => /json/}, :as => :json_only get '/привет' => "foo#foo", :as => :hello get '(/o/:organization)/search/:q' => "foo#foo", as: :search resources :sessions, :only => [:new, :create], :protocol => 'https' get '/' => 'sso#login', host: 'sso.example.com', as: :sso get "/" => "a#b", subdomain: 'www', host: 'example.com', port: 88, as: :secret_root resources :portals, :port => 8080, only: [:index] get '/with_defaults' => 'foo#foo', defaults: { bar: 'tested', format: :json }, format: :true namespace :api, format: true, defaults: {format: 'json'} do get "/purchases" => "purchases#index" end resources :budgies, only: [:show, :index] do get "descendents" end namespace :backend, path: '', constraints: {subdomain: 'backend'} do root to: 'backend#index' end end end