js-routes-1.2.4/0000755000004100000410000000000012666751521013514 5ustar www-datawww-datajs-routes-1.2.4/Rakefile0000644000004100000410000000070312666751521015161 0ustar www-datawww-data# 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' RSpec::Core::RakeTask.new(:spec) task :test_all => :appraisal # test all rails task :default => :specjs-routes-1.2.4/Gemfile0000644000004100000410000000013512666751521015006 0ustar www-datawww-datasource "http://rubygems.org" # Specify your gem's dependencies in js-routes.gemspec gemspec js-routes-1.2.4/.rspec0000644000004100000410000000001012666751521014620 0ustar www-datawww-data--color js-routes-1.2.4/LICENSE.txt0000644000004100000410000000204112666751521015334 0ustar www-datawww-dataCopyright (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. js-routes-1.2.4/spec/0000755000004100000410000000000012666751521014446 5ustar www-datawww-datajs-routes-1.2.4/spec/js_routes/0000755000004100000410000000000012666751521016463 5ustar www-datawww-datajs-routes-1.2.4/spec/js_routes/default_serializer_spec.rb0000644000004100000410000000047312666751521023703 0ustar www-datawww-datadescribe JsRoutes, "#default_serializer" do before(:each) do evaljs(JsRoutes.generate({})) end it "should provide this method" do expect(evaljs("Routes.default_serializer({a: 1, b: [2,3], c: {d: 4, e: 5}, f: ''})")).to eq( "a=1&b%5B%5D=2&b%5B%5D=3&c%5Bd%5D=4&c%5Be%5D=5&f=" ) end end js-routes-1.2.4/spec/js_routes/generated_javascript_spec.rb0000644000004100000410000000603612666751521024213 0ustar www-datawww-datarequire 'spec_helper' require "fileutils" describe JsRoutes do before(:each) do evaljs(JsRoutes.generate) end describe "generated js" do subject { JsRoutes.generate } it "should set the default serializer when none is configured" do is_expected.to match(%r(custom_serializer: null,\s+serialize: function\(object\) {\s+if \(\(this\.custom_serializer != null\) && this.get_object_type\(this\.custom_serializer\) === \"function\"\) {\s+return this\.custom_serializer\(object\);\s+} else {\s+return this\.default_serializer\(object\);\s+}\s+},)) end it "should include a comment in the header" do app_class = "App" is_expected.to include("File generated by js-routes #{JsRoutes::VERSION}") is_expected.to include("Based on Rails routes of #{app_class}") end it "should call route function for each route" do is_expected.to include("inboxes_path: Utils.route(") end it "should have correct function without arguments signature" do is_expected.to include("inboxes_path: Utils.route([]") end it "should have correct function with arguments signature" do is_expected.to include("inbox_message_path: Utils.route([\"inbox_id\",\"id\"]") end it "should have correct function signature with unordered hash" do is_expected.to include("inbox_message_attachment_path: Utils.route([\"inbox_id\",\"message_id\",\"id\"]") end it "should have correct function comment with options argument" do is_expected.to include("// function(options)\n inboxes_path: Utils.route") end it "should have correct function comment with arguments" do is_expected.to include("// function(inbox_id, message_id, options)\n new_inbox_message_attachment_path: Utils.route") end it "routes should be sorted in alphabetical order" do expect(subject.index("book_path")).to be <= subject.index("inboxes_path") end end describe ".generate!" do let(:name) { Rails.root.join('app', 'assets', 'javascripts', 'routes.js') } before(:each) do FileUtils.rm_f(name) JsRoutes.generate!({:file => 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 if JsRoutes::SPROCKETS3 let(:routes_path){ "#{Rails.root.join 'config', 'routes.rb'}" } before { expect(self).to receive(:depend_on).with routes_path } end 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\",\"id\"]") end end end js-routes-1.2.4/spec/js_routes/rails_routes_compatibility_spec.rb0000644000004100000410000002720412666751521025473 0ustar www-datawww-datarequire "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(routes.inboxes_path()) end it "should generate member routing" do expect(evaljs("Routes.inbox_path(1)")).to eq(routes.inbox_path(1)) end it "should support 0 as a member parameter" do expect(evaljs("Routes.inbox_path(0)")).to eq(routes.inbox_path(0)) end it "should support 0 as a to_param option" do expect(evaljs("Routes.inbox_path({to_param: 0})")).to eq(routes.inbox_path(0)) end it "should support 0 as an id option" do expect(evaljs("Routes.inbox_path({id: 0})")).to eq(routes.inbox_path(0)) end it "should generate nested routing with one parameter" do expect(evaljs("Routes.inbox_messages_path(1)")).to eq(routes.inbox_messages_path(1)) end it "should generate nested routing" do expect(evaljs("Routes.inbox_message_path(1,2)")).to eq(routes.inbox_message_path(1, 2)) end it "should generate routing with format" do expect(evaljs("Routes.inbox_path(1, {format: 'json'})")).to eq(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(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(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(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(routes.inbox_path(1, :expanded => true, :anchor => "hello")) end it "should use irregular ActiveSupport pluralizations" do expect(evaljs("Routes.budgies_path()")).to eq(routes.budgies_path) expect(evaljs("Routes.budgie_path(1)")).to eq(routes.budgie_path(1)) expect(evaljs("Routes.budgy_path")).to eq(nil) expect(evaljs("Routes.budgie_descendents_path(1)")).to eq(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(routes.api_purchases_path) end it "should support default format override" do expect(evaljs("Routes.api_purchases_path({format: 'xml'})")).to eq(routes.api_purchases_path(format: 'xml')) 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 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(routes.support_path(:page => 3)) end end it "shouldn't require the format" do expect(evaljs("Routes.json_only_path({format: 'json'})")).to eq(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(routes.inboxes_path(:a => '', :b => 1)) end it "should support utf-8 route" do expect(evaljs("Routes.hello_path()")).to eq(routes.hello_path) end it "should support root_path" do expect(evaljs("Routes.root_path()")).to eq(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(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(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( 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(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(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(routes.book_path('thrillers', 1)) end it "should support routes globbing as array" do expect(evaljs("Routes.book_path(['thrillers'], 1)")).to eq(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(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(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(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(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(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(routes.search_path(:q => 'hello')) end it "should support nested object null parameters" do expect(evaljs("Routes.inboxes_path({hello: {world: null}})")).to eq(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(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(routes.things_path) end it "should not require the optional parts as arguments" do #TODO: fix this inconsistence pending expect(evaljs("Routes.thing_path(null, 5)")).to eq(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(routes.thing_path(5, :optional_id => nil)) end it "should treat null as non-given optional part" do expect(evaljs("Routes.thing_path(5, {optional_id: null})")).to eq(routes.thing_path(5, :optional_id => nil)) end end context "and including them" do it "should include the optional parts" do expect(evaljs("Routes.things_path({optional_id: 5})")).to eq(routes.things_path(:optional_id => 5)) end context "on nested optional parts" do it "should include everything that is not optional" do expect(evaljs("Routes.classic_path({controller: 'classic', action: 'edit'})")).to eq(routes.classic_path(controller: :classic, action: :edit)) 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)") }.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(routes.inboxes_path()) end end context "when arguments are objects" do let(:inbox) {Struct.new(:id, :to_param).new(1,"my")} it "should use id property of the object in path" do expect(evaljs("Routes.inbox_path({id: 1})")).to eq(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(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(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(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(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(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(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(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(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 js-routes-1.2.4/spec/js_routes/amd_compatibility_spec.rb0000644000004100000410000000235612666751521023522 0ustar www-datawww-datarequire "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 =< "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 serializer is 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 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#{routes.inbox_path(1)}") end it "should render routing with prefix set in JavaScript" do evaljs("Routes.options.prefix = '/newprefix/'") expect(evaljs("Routes.inbox_path(1)")).to eq("/newprefix#{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] + 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#{routes.inbox_path(1)}") end it "should render routing with prefix set in JavaScript" do evaljs("Routes.options.prefix = '/newprefix'") expect(evaljs("Routes.inbox_path(1)")).to eq("/newprefix#{routes.inbox_path(1)}") end end context "when default_format is specified" do let(:_options) { {:default_format => "json"} } let(:_warnings) { nil } it "should render routing with default_format" do expect(evaljs("Routes.inbox_path(1)")).to eq(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(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(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(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(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(routes.no_format_path()) expect(evaljs("Routes.no_format_path({format: 'json'})")).to eq(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 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(routes.things_path(:optional_id => 12, :format => "json")) 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(routes.inbox_messages_path(:inbox_id => 12)) 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(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(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(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(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(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(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(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(routes.inbox_path(1)) expect(evaljs("Routes.inboxMessagesPath(10)")).to eq(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(routes.inbox_path(1)) expect(evaljs("Routes.inbox_url")).to be_nil end end context 'with deprecated, non-boolean config value' do around(:each) do |example| ActiveSupport::Deprecation.silence do example.run end end context "with host" do let(:_options) { { :url_links => "http://localhost" } } it "should generate path and url links" do expect(evaljs("Routes.inbox_path")).not_to be_nil expect(evaljs("Routes.inbox_url")).not_to be_nil expect(evaljs("Routes.inbox_path(1)")).to eq(routes.inbox_path(1)) expect(evaljs("Routes.inbox_url(1)")).to eq("http://localhost#{routes.inbox_path(1)}") expect(evaljs("Routes.inbox_url(1, { test_key: \"test_val\" })")).to eq("http://localhost#{routes.inbox_path(1, :test_key => "test_val")}") end end context "with invalid host" do it "should raise error" do expect { JsRoutes.generate({ :url_links => "localhost" }) }.to raise_error RuntimeError end end context "with host and camel_case" do let(:_options) { { :camel_case => true, :url_links => "http://localhost" } } it "should generate path and url links" do expect(evaljs("Routes.inboxPath")).not_to be_nil expect(evaljs("Routes.inboxUrl")).not_to be_nil expect(evaljs("Routes.inboxPath(1)")).to eq(routes.inbox_path(1)) expect(evaljs("Routes.inboxUrl(1)")).to eq("http://localhost#{routes.inbox_path(1)}") end end context "with host and prefix" do let(:_options) { { :prefix => "/api", :url_links => "https://example.com" } } it "should generate path and url links" do expect(evaljs("Routes.inbox_path")).not_to be_nil expect(evaljs("Routes.inbox_url")).not_to be_nil expect(evaljs("Routes.inbox_path(1)")).to eq("/api#{routes.inbox_path(1)}") expect(evaljs("Routes.inbox_url(1)")).to eq("https://example.com/api#{routes.inbox_path(1)}") end 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#{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#{routes.new_session_path}") end it "does not override host when specified in route" do expect(evaljs("Routes.sso_url()")).to eq(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#{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#{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#{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#{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#{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#{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#{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" + routes.sso_path) end it "does not override port when specified in route" do expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080#{routes.portals_path}") 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#{routes.inbox_path(1)}") expect(evaljs("Routes.newSessionUrl()")).to eq("https://example.com#{routes.new_session_path}") expect(evaljs("Routes.ssoUrl()")).to eq(routes.sso_url) expect(evaljs("Routes.portalsUrl()")).to eq("http://example.com:8080#{routes.portals_path}") 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#{routes.inbox_path(1)}") expect(evaljs("Routes.new_session_url()")).to eq("https://example.com/api#{routes.new_session_path}") expect(evaljs("Routes.sso_url()")).to eq("http://sso.example.com/api#{routes.sso_path}") expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080/api#{routes.portals_path}") 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#{routes.inbox_path(1)}") expect(evaljs("Routes.new_session_url()")).to eq("https://example.com#{routes.new_session_path}") expect(evaljs("Routes.sso_url()")).to eq(routes.sso_url) expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080#{routes.portals_path}") 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['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#{routes.inbox_path(1)}") expect(evaljs("Routes.inbox_url(1, { test_key: \"test_val\" })")).to eq("http://current.example.com#{routes.inbox_path(1, :test_key => "test_val")}") expect(evaljs("Routes.new_session_url()")).to eq("https://current.example.com#{routes.new_session_path}") expect(evaljs("Routes.sso_url()")).to eq("http://sso.example.com#{routes.sso_path}") end it "uses host option as an argument" do expect(evaljs("Routes.portals_url({host: 'another.com'})")).to eq(routes.portals_url(host: 'another.com')) end it "uses port option as an argument" do expect(evaljs("Routes.portals_url({host: 'localhost', port: 8080})")).to eq(routes.portals_url(host: 'localhost', port: 8080)) end it "uses protocol option as an argument" do expect(evaljs("Routes.portals_url({host: 'localhost', protocol: 'https'})")).to eq(routes.portals_url(protocol: 'https', host: 'localhost')) 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(routes.inboxes_path()) expect(evaljs("Routes.inbox(2)")).to eq(routes.inbox_path(2)) end context "with url_links option" do context "with deprecated url_links config value" do around(:each) do |example| ActiveSupport::Deprecation.silence do example.run end end let(:_options) { { :compact => true, :url_links => "http://localhost" } } it "should not strip urls" do expect(evaljs("Routes.inbox(1)")).to eq(routes.inbox_path(1)) expect(evaljs("Routes.inbox_url(1)")).to eq("http://localhost#{routes.inbox_path(1)}") end end end end end js-routes-1.2.4/spec/js_routes/zzz_last_post_rails_init_spec.rb0000644000004100000410000000707012666751521025170 0ustar www-datawww-data# 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(/root\.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(/root\.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 js-routes-1.2.4/spec/spec_helper.rb0000644000004100000410000001004112666751521017260 0ustar www-datawww-data# 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 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 def 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 do resources :messages do resources :attachments end end root :to => "inboxes#index" namespace :admin do resources :users end scope "/returns/:return" do resources :objects end resources :returns scope "(/optional/:optional_id)" do resources :things end get "/:controller(/:action(/:id))" => "classic#classic", :as => :classic get "/other_optional/(:optional_id)" => "foo#foo", :as => :foo 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, :destroy], :protocol => 'https' get '/' => 'sso#login', host: 'sso.example.com', as: :sso resources :portals, :port => 8080 namespace :api, format: true, defaults: {format: 'json'} do get "/purchases" => "purchases#index" end resources :budgies do get "descendents" end end 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::Object value.to_h.map do |k,v| [k, inspectify(v)] end.to_h when String, nil value else raise "wtf #{value.class}?" end end jscontext[:log] = lambda do |context, value| puts inspectify(value).to_json end end end js-routes-1.2.4/spec/dummy/0000755000004100000410000000000012666751521015601 5ustar www-datawww-datajs-routes-1.2.4/spec/dummy/config/0000755000004100000410000000000012666751521017046 5ustar www-datawww-datajs-routes-1.2.4/spec/dummy/config/routes.rb0000644000004100000410000000463512666751521020724 0ustar www-datawww-dataApp.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 js-routes-1.2.4/spec/dummy/app/0000755000004100000410000000000012666751521016361 5ustar www-datawww-datajs-routes-1.2.4/spec/dummy/app/assets/0000755000004100000410000000000012666751521017663 5ustar www-datawww-datajs-routes-1.2.4/spec/dummy/app/assets/javascripts/0000755000004100000410000000000012666751521022214 5ustar www-datawww-datajs-routes-1.2.4/spec/dummy/app/assets/javascripts/.gitkeep0000644000004100000410000000000012666751521023633 0ustar www-datawww-datajs-routes-1.2.4/.travis.yml0000644000004100000410000000104612666751521015626 0ustar www-datawww-datalanguage: ruby cache: bundler rvm: - 1.9.3 - 2.0 - 2.1 - 2.2 - jruby-19mode - ruby-head - jruby-head gemfile: - gemfiles/rails32.gemfile - gemfiles/rails40.gemfile - gemfiles/rails40_sprockets3.gemfile - gemfiles/rails41.gemfile - gemfiles/rails41_sprockets3.gemfile - gemfiles/rails42.gemfile - gemfiles/rails42_sprockets3.gemfile sudo: false notifications: email: - agresso@gmail.com branches: only: - master matrix: allow_failures: - rvm: jruby-19mode - rvm: ruby-head - rvm: jruby-head js-routes-1.2.4/lib/0000755000004100000410000000000012666751521014262 5ustar www-datawww-datajs-routes-1.2.4/lib/js_routes.rb0000644000004100000410000001711012666751521016624 0ustar www-datawww-datarequire '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: nil, url_links: false, camel_case: false, default_url_options: {}, compact: false, serializer: nil } 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] class Options < Struct.new(*DEFAULTS.keys) def to_hash Hash[*members.zip(values).flatten(1)].symbolize_keys end end # # API # class << self def setup(&block) options.tap(&block) if block end def options @options ||= Options.new.tap do |opts| DEFAULTS.each_pair {|k,v| opts[k] = v} end end def generate(opts = {}) # Ensure routes are loaded. If they're not, load them. if Rails.application.routes.named_routes.to_a.empty? Rails.application.reload_routes! end 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 = {}) @options = self.class.options.to_hash.merge(options) end def generate { "GEM_VERSION" => JsRoutes::VERSION, "APP_CLASS" => Rails.application.class.to_s, "NAMESPACE" => @options[:namespace], "DEFAULT_URL_OPTIONS" => json(@options[:default_url_options].merge(deprecate_url_options)), "PREFIX" => @options[:prefix] || "", "NODE_TYPES" => json(NODE_TYPES), "SERIALIZER" => @options[:serializer] || "null", "ROUTES" => js_routes, }.inject(File.read(File.dirname(__FILE__) + "/routes.js")) do |js, (key, value)| js.gsub!(key, value) end end def deprecate_url_options result = {} if @options.key?(:default_format) warn("default_format option is deprecated. Use default_url_options = { format: } instead") result.merge!( format: @options[:default_format] ) end if @options[:url_links].is_a?(String) ActiveSupport::Deprecation.warn('js-routes url_links config value must be a boolean. Use default_url_options for specifying a default host.') raise "invalid URL format in url_links (ex: http[s]://example.com)" if @options[:url_links].match(URI::Parser.new.make_regexp(%w(http https))).nil? uri = URI.parse(@options[:url_links]) default_port = uri.scheme == "https" ? 443 : 80 port = uri.port == default_port ? nil : uri.port result.merge!( host: uri.host, port: port, protocol: uri.scheme, ) end result 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.options['file'] File.open(Rails.root.join(file_name || DEFAULT_PATH), 'w') do |f| f.write generate end end end protected def js_routes js_routes = Rails.application.routes.named_routes.to_a.sort_by(&:to_s).flat_map do |_, 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 build_route_if_match(route) end end.compact "{\n" + js_routes.join(",\n") + "}\n" 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, @options[:exclude]) || !any_match?(route, parent_route, @options[: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 @options[: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.clone optional_parts = route.parts - required_parts default_parts = route.defaults.reject do |part, _| FILTERED_DEFAULT_PARTS.include?(part) end [ required_parts, optional_parts, serialize(route.path.spec, parent_spec), default_parts ].map do |argument| json(argument) end.join(", ") end def generate_url_link(name, route_name, route_arguments, route) return "" unless @options[: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 @options[: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 js-routes-1.2.4/lib/js_routes/0000755000004100000410000000000012666751521016277 5ustar www-datawww-datajs-routes-1.2.4/lib/js_routes/engine.rb0000644000004100000410000000120212666751521020064 0ustar www-datawww-datarequire 'sprockets/version' class JsRoutes SPROCKETS3 = Gem::Version.new(Sprockets::VERSION) >= Gem::Version.new('3.0.0') class Engine < ::Rails::Engine initializer 'js-routes.dependent_on_routes', after: "sprockets.environment" do if Rails.application.assets.respond_to?(:register_preprocessor) routes = Rails.root.join('config', 'routes.rb').to_s Rails.application.assets.register_preprocessor 'application/javascript', :'js-routes_dependent_on_routes' do |ctx,data| ctx.depend_on(routes) if ctx.logical_path == 'js-routes' data end end end unless SPROCKETS3 end end js-routes-1.2.4/lib/js_routes/version.rb0000644000004100000410000000004712666751521020312 0ustar www-datawww-dataclass JsRoutes VERSION = "1.2.4" end js-routes-1.2.4/lib/tasks/0000755000004100000410000000000012666751521015407 5ustar www-datawww-datajs-routes-1.2.4/lib/tasks/js_routes.rake0000644000004100000410000000030112666751521020262 0ustar www-datawww-datanamespace :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 js-routes-1.2.4/lib/routes.js.coffee0000644000004100000410000002563712666751521017404 0ustar www-datawww-data### File generated by js-routes GEM_VERSION Based on Rails routes of APP_CLASS ### # root is this root = (exports ? this) ParameterMissing = (@message) -> # ParameterMissing:: = new Error() defaults = prefix: "PREFIX" default_url_options: DEFAULT_URL_OPTIONS NodeTypes = NODE_TYPES ReservedOptions = [ 'anchor' 'trailing_slash' 'host' 'port' 'protocol' ] Utils = 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("&") custom_serializer: SERIALIZER serialize: (object) -> 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)) args.pop() || {} else {} looks_like_serialized_model: (object) -> # consider object a model if it have a path identifier properties like id and to_param "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 property = object.to_param else if "id" of object 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: (default_parts, required_parameters, optional_parts, actual_parameters) -> options = @extract_options(required_parameters.length, actual_parameters) if actual_parameters.length > required_parameters.length throw new Error("Too many parameters provided for path") options = @merge(defaults.default_url_options, default_parts, options) result = {} url_parameters = {} result['url_parameters'] = url_parameters for own key, value of options if ReservedOptions.indexOf(key) >= 0 result[key] = value else url_parameters[key] = value for value, i in required_parameters when i < actual_parameters.length url_parameters[value] = actual_parameters[i] result build_route: (required_parameters, optional_parts, route, default_parts, full_url, args) -> args = Array::slice.call(args) options = @normalize_options(default_parts, required_parameters, optional_parts, 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) return "" if optional and (((left[0] == NodeTypes.SYMBOL or left[0] == NodeTypes.CAT) and not left_part) or ((right[0] == NodeTypes.SYMBOL or right[0] == NodeTypes.CAT) and not right_part)) "#{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") # # 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 = defaults.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: (required_parts, optional_parts, route_spec, default_parts, full_url) -> path_fn = -> Utils.build_route( required_parts, optional_parts, route_spec, default_parts, 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' protocol = route_defaults.protocol || Utils.current_protocol() hostname = route_defaults.host || window.location.hostname port = route_defaults.port || (Utils.current_port() unless route_defaults.host) port = if port then ":#{port}" else '' protocol + "://" + hostname + port has_location: -> typeof window != 'undefined' && typeof window.location != 'undefined' 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) # globalJsObject createGlobalJsRoutesObject = -> # namespace function, private namespace = (mainRoot, namespaceString) -> parts = (if namespaceString then namespaceString.split(".") else []) return unless parts.length current = parts.shift() mainRoot[current] = mainRoot[current] or {} namespace mainRoot[current], parts.join(".") # object namespace(root, "NAMESPACE") root.NAMESPACE = ROUTES root.NAMESPACE.options = defaults root.NAMESPACE.default_serializer = (object, prefix) -> Utils.default_serializer(object, prefix) root.NAMESPACE # Set up Routes appropriately for the environment. if typeof define is "function" and define.amd # AMD define [], -> createGlobalJsRoutesObject() else # Browser globals createGlobalJsRoutesObject() js-routes-1.2.4/lib/js-routes.rb0000644000004100000410000000002412666751521016536 0ustar www-datawww-datarequire 'js_routes' js-routes-1.2.4/lib/routes.js0000644000004100000410000003167112666751521016151 0ustar www-datawww-data/* File generated by js-routes GEM_VERSION Based on Rails routes of APP_CLASS */ (function() { var NodeTypes, ParameterMissing, ReservedOptions, Utils, createGlobalJsRoutesObject, defaults, root, hasProp = {}.hasOwnProperty, slice = [].slice; root = typeof exports !== "undefined" && exports !== null ? exports : this; ParameterMissing = function(message) { this.message = message; }; ParameterMissing.prototype = new Error(); defaults = { prefix: "PREFIX", default_url_options: DEFAULT_URL_OPTIONS }; NodeTypes = NODE_TYPES; ReservedOptions = ['anchor', 'trailing_slash', 'host', 'port', 'protocol']; Utils = { 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("&"); }, custom_serializer: SERIALIZER, serialize: function(object) { if ((this.custom_serializer != null) && this.get_object_type(this.custom_serializer) === "function") { return this.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; 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))) { return args.pop() || {}; } else { return {}; } }, looks_like_serialized_model: function(object) { return "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) { property = object.to_param; } else if ("id" in object) { 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(default_parts, required_parameters, optional_parts, actual_parameters) { var i, j, key, len, options, result, url_parameters, value; options = this.extract_options(required_parameters.length, actual_parameters); if (actual_parameters.length > required_parameters.length) { throw new Error("Too many parameters provided for path"); } options = this.merge(defaults.default_url_options, default_parts, options); result = {}; url_parameters = {}; result['url_parameters'] = url_parameters; for (key in options) { if (!hasProp.call(options, key)) continue; value = options[key]; if (ReservedOptions.indexOf(key) >= 0) { result[key] = value; } else { url_parameters[key] = value; } } for (i = j = 0, len = required_parameters.length; j < len; i = ++j) { value = required_parameters[i]; if (i < actual_parameters.length) { url_parameters[value] = actual_parameters[i]; } } return result; }, build_route: function(required_parameters, optional_parts, route, default_parts, full_url, args) { var options, parameters, result, url, url_params; args = Array.prototype.slice.call(args); options = this.normalize_options(default_parts, required_parameters, optional_parts, 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 && (((left[0] === NodeTypes.SYMBOL || left[0] === NodeTypes.CAT) && !left_part) || ((right[0] === NodeTypes.SYMBOL || right[0] === NodeTypes.CAT) && !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"); } }, 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 = defaults.prefix; if (prefix !== "") { prefix = (prefix.match("/$") ? prefix : prefix + "/"); } return prefix; }, route: function(required_parts, optional_parts, route_spec, default_parts, full_url) { var path_fn; path_fn = function() { return Utils.build_route(required_parts, optional_parts, route_spec, default_parts, 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; if (typeof route_defaults === 'string') { return route_defaults; } protocol = route_defaults.protocol || Utils.current_protocol(); hostname = route_defaults.host || window.location.hostname; port = route_defaults.port || (!route_defaults.host ? Utils.current_port() : void 0); port = port ? ":" + port : ''; return protocol + "://" + hostname + port; }, has_location: function() { return typeof window !== 'undefined' && typeof window.location !== 'undefined'; }, 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; } } }; createGlobalJsRoutesObject = function() { var namespace; namespace = function(mainRoot, namespaceString) { var current, parts; parts = (namespaceString ? namespaceString.split(".") : []); if (!parts.length) { return; } current = parts.shift(); mainRoot[current] = mainRoot[current] || {}; return namespace(mainRoot[current], parts.join(".")); }; namespace(root, "NAMESPACE"); root.NAMESPACE = ROUTES; root.NAMESPACE.options = defaults; root.NAMESPACE.default_serializer = function(object, prefix) { return Utils.default_serializer(object, prefix); }; return root.NAMESPACE; }; if (typeof define === "function" && define.amd) { define([], function() { return createGlobalJsRoutesObject(); }); } else { createGlobalJsRoutesObject(); } }).call(this); js-routes-1.2.4/gemfiles/0000755000004100000410000000000012666751521015307 5ustar www-datawww-datajs-routes-1.2.4/gemfiles/rails41.gemfile0000644000004100000410000000022012666751521020112 0ustar www-datawww-data# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.1.1" gem "sprockets", "< 3" gemspec :path => "../" js-routes-1.2.4/gemfiles/rails42_sprockets3.gemfile0000644000004100000410000000022312666751521022276 0ustar www-datawww-data# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.2.1" gem "sprockets", "~> 3.0" gemspec :path => "../" js-routes-1.2.4/gemfiles/rails41_sprockets3.gemfile0000644000004100000410000000022312666751521022275 0ustar www-datawww-data# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.1.1" gem "sprockets", "~> 3.0" gemspec :path => "../" js-routes-1.2.4/gemfiles/rails40_sprockets3.gemfile0000644000004100000410000000022312666751521022274 0ustar www-datawww-data# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.0.5" gem "sprockets", "~> 3.0" gemspec :path => "../" js-routes-1.2.4/gemfiles/rails40.gemfile0000644000004100000410000000022012666751521020111 0ustar www-datawww-data# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.0.5" gem "sprockets", "< 3" gemspec :path => "../" js-routes-1.2.4/gemfiles/rails42.gemfile0000644000004100000410000000022012666751521020113 0ustar www-datawww-data# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 4.2.1" gem "sprockets", "< 3" gemspec :path => "../" js-routes-1.2.4/gemfiles/rails32.gemfile0000644000004100000410000000020712666751521020117 0ustar www-datawww-data# This file was generated by Appraisal source "http://rubygems.org" gem "railties", "~> 3.2.18" gem "tzinfo" gemspec :path => "../" js-routes-1.2.4/Readme.md0000644000004100000410000001604412666751521015240 0ustar www-datawww-data# JsRoutes [![Build Status](https://travis-ci.org/railsware/js-routes.svg?branch=master)](https://travis-ci.org/railsware/js-routes) 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 ``` Available options: * `default_url_options` - default parameters used when generating URLs * Note that only specific options are supported at this time. * Example: {:format => "json", :trailing\_slash => true, :protocol => "https", :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. * Example: `http://yourdomain.com`. This will cause route helpers to generate full path only. * Default: blank * `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 * 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. ### 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"}) ``` ## 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'] ``` ## 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 js-routes-1.2.4/.gitignore0000644000004100000410000000166612666751521015515 0ustar www-datawww-data# 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 js-routes-1.2.4/Appraisals0000644000004100000410000000054612666751521015543 0ustar www-datawww-dataappraise "rails32" do gem "railties", "~> 3.2.18" gem 'tzinfo' end {rails40: '4.0.5', rails41: '4.1.1', rails42: '4.2.1'}.each do |rails, version| appraise "#{rails}" do gem "railties", "~> #{version}" gem "sprockets", "< 3" end appraise "#{rails}-sprockets3" do gem "railties", "~> #{version}" gem "sprockets", "~> 3.0" end endjs-routes-1.2.4/app/0000755000004100000410000000000012666751521014274 5ustar www-datawww-datajs-routes-1.2.4/app/assets/0000755000004100000410000000000012666751521015576 5ustar www-datawww-datajs-routes-1.2.4/app/assets/javascripts/0000755000004100000410000000000012666751521020127 5ustar www-datawww-datajs-routes-1.2.4/app/assets/javascripts/js-routes.js.erb0000644000004100000410000000025412666751521023170 0ustar www-datawww-data<%# encoding: UTF-8 %> <% depend_on "#{Rails.root.join 'config', 'routes.rb'}" if JsRoutes::SPROCKETS3 %> <%= JsRoutes.assert_usable_configuration! && JsRoutes.generate %> js-routes-1.2.4/js-routes.gemspec0000644000004100000410000000261312666751521017016 0ustar www-datawww-data# 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"]) s.add_development_dependency(%q, [">= 0.5.2"]) if defined?(JRUBY_VERSION) s.add_development_dependency(%q, [">= 2.0.4"]) else if RUBY_VERSION >= "2.0.0" s.add_development_dependency(%q) end s.add_development_dependency(%q, [">= 0.12.1"]) end end js-routes-1.2.4/CHANGELOG.md0000644000004100000410000000464712666751521015340 0ustar www-datawww-data## master ## 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) js-routes-1.2.4/temp0000644000004100000410000000213712666751521014407 0ustar www-datawww-data#, @dispatcher=false, @constraints={:required_defaults=>[]}, @defaults={}, @required_defaults=nil, @required_parts=[], @parts=[], @decorated_ast=nil, @precedence=61> #, @dispatcher=false, @constraints={:required_defaults=>[], :request_method=>/^GET$/}, @defaults={}, @required_defaults=nil, @required_parts=[], @parts=[:page, :format], @decorated_ast=nil, @precedence=0> js-routes-1.2.4/.document0000644000004100000410000000006712666751521015336 0ustar www-datawww-datalib/**/*.rb bin/* - features/**/*.feature LICENSE.txt js-routes-1.2.4/Guardfile0000644000004100000410000000014512666751521015341 0ustar www-datawww-dataguard 'coffeescript', :output => 'lib', :all_on_start => true do watch(%r{^lib/(.+\.coffee)$}) end