versionist-2.0.1/0000755000004100000410000000000013516730105013750 5ustar www-datawww-dataversionist-2.0.1/lib/0000755000004100000410000000000013516730105014516 5ustar www-datawww-dataversionist-2.0.1/lib/generators/0000755000004100000410000000000013516730105016667 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/0000755000004100000410000000000013516730105021074 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/new_presenter/0000755000004100000410000000000013516730105023754 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/new_presenter/templates/0000755000004100000410000000000013516730105025752 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/new_presenter/templates/new_presenter.rb0000644000004100000410000000052713516730105031163 0ustar www-datawww-dataclass <%= module_name %>::<%= class_name%>Presenter < <%= module_name %>::BasePresenter def initialize(<%= file_name %>) @<%= file_name %> = <%= file_name %> end def as_json(options={}) # fill me in... end def to_xml(options={}, &block) xml = options[:builder] ||= Builder::XmlMarkup.new # fill me in... end end versionist-2.0.1/lib/generators/versionist/new_presenter/templates/new_presenter_spec.rb0000644000004100000410000000014513516730105032171 0ustar www-datawww-datarequire '<%= @rspec_require_file %>' describe <%= module_name %>::<%= class_name%>Presenter do end versionist-2.0.1/lib/generators/versionist/new_presenter/templates/new_presenter_test_rails_5.rb0000644000004100000410000000030013516730105033625 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::<%= class_name%>PresenterTest < ActiveSupport::TestCase # Replace this with your real tests. test "the truth" do assert true end end versionist-2.0.1/lib/generators/versionist/new_presenter/templates/new_presenter_test.rb0000644000004100000410000000027513516730105032222 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::<%= class_name%>PresenterTest < Test::Unit::TestCase # Replace this with your real tests. test "the truth" do assert true end end versionist-2.0.1/lib/generators/versionist/new_presenter/new_presenter_generator.rb0000644000004100000410000000320213516730105031224 0ustar www-datawww-datamodule Versionist class NewPresenterGenerator < Rails::Generators::NamedBase include InflectorFixes include RspecHelper desc "creates a new presenter for an existing API version" source_root File.expand_path('../templates', __FILE__) argument :module_name, :type => :string def new_presenter in_root do raise "API module namespace #{module_name} doesn't exist. Please run \'rails generate versionist:new_api_version\' generator first" if !File.exists?("app/presenters/#{module_name_for_path(module_name)}") template 'new_presenter.rb', File.join("app", "presenters", "#{module_name_for_path(module_name)}", "#{file_name}_presenter.rb") end end def new_presenter_test in_root do case Versionist.configuration.configured_test_framework when :test_unit if Versionist.older_than_rails_5? template 'new_presenter_test.rb', File.join("test", "presenters", "#{module_name_for_path(module_name)}", "#{file_name}_presenter_test.rb") else template 'new_presenter_test_rails_5.rb', File.join("test", "presenters", "#{module_name_for_path(module_name)}", "#{file_name}_presenter_test_rails_5.rb") end when :rspec @rspec_require_file = rspec_helper_filename template 'new_presenter_spec.rb', File.join("spec", "presenters", "#{module_name_for_path(module_name)}", "#{file_name}_presenter_spec.rb"), :assigns => { :rspec_require_file => @rspec_require_file } else say "Unsupported test_framework: #{Versionist.configuration.configured_test_framework}" end end end end end versionist-2.0.1/lib/generators/versionist/new_presenter/USAGE0000644000004100000410000000054313516730105024545 0ustar www-datawww-dataDescription: Creates a new presenter class with the given name under the given version Example: rails generate versionist:new_presenter foo V2_0_0 This will create: app/presenters/v2_0_0/foo_presenter.rb In addition this will create a test for the new controller using the test_framework currently configured in your Rails app. versionist-2.0.1/lib/generators/versionist/inflector_fixes.rb0000644000004100000410000000056513516730105024612 0ustar www-datawww-datamodule Versionist # Various fixes for quirks in Rails' inflector module InflectorFixes # Transforms a module name for use in a route def module_name_for_route(module_name) module_name.gsub(/_{1}/, "__") end # Transforms a module name for use in a file path def module_name_for_path(module_name) module_name.underscore end end end versionist-2.0.1/lib/generators/versionist/copy_api_version/0000755000004100000410000000000013516730105024444 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/copy_api_version/copy_api_version_generator.rb0000644000004100000410000002556513516730105032424 0ustar www-datawww-datarequire 'yard' require 'fileutils' module Versionist class CopyApiVersionGenerator < Rails::Generators::Base include InflectorFixes desc "copies an existing API version a new API version" source_root File.expand_path('../templates', __FILE__) argument :old_version, :type => :string argument :old_module_name, :type => :string argument :new_version, :type => :string argument :new_module_name, :type => :string def copy_routes in_root do if RUBY_VERSION =~ /1.8/ || !defined?(RUBY_ENGINE) || RUBY_ENGINE != "ruby" log "ERROR: Cannot copy routes as this feature relies on the Ripper library, which is only available in MRI 1.9." return end parser = YARD::Parser::SourceParser.parse_string(File.read("config/routes.rb")) existing_routes = nil parser.enumerator.first.traverse do |node| existing_routes = node.source if node.type == :fcall && node.source =~ /api_version.*:?module\s*(=>|:)\s*("|')#{module_name_for_route(old_module_name)}("|')/ end if !existing_routes.nil? copied_routes = String.new(existing_routes) copied_routes.gsub!(/"#{module_name_for_route(old_module_name)}"/, "\"#{module_name_for_route(new_module_name)}\"") copied_routes.gsub!(/#{old_version}/, new_version) route copied_routes else say "No routes found in config/routes.rb for #{old_version}" end end end def copy_controllers in_root do if File.exists? "app/controllers/#{module_name_for_path(old_module_name)}" log "Copying all files from app/controllers/#{module_name_for_path(old_module_name)} to app/controllers/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "app/controllers/#{module_name_for_path(old_module_name)}", "app/controllers/#{module_name_for_path(new_module_name)}" Dir.glob("app/controllers/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No controllers found in app/controllers for #{old_version}" end end end # due to the inflector quirks we can't use hook_for :test_framework def copy_controller_tests in_root do case Versionist.configuration.configured_test_framework when :test_unit if File.exists? "#{Versionist.test_path}/#{module_name_for_path(old_module_name)}" log "Copying all files from #{Versionist.test_path}/#{module_name_for_path(old_module_name)} to #{Versionist.test_path}/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "#{Versionist.test_path}/#{module_name_for_path(old_module_name)}", "#{Versionist.test_path}/#{module_name_for_path(new_module_name)}" Dir.glob("#{Versionist.test_path}/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No tests found in #{Versionist.test_path} for #{old_version}" end if Versionist.older_than_rails_5? if File.exists? "test/integration/#{module_name_for_path(old_module_name)}" log "Copying all files from test/integration/#{module_name_for_path(old_module_name)} to test/integration/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "test/integration/#{module_name_for_path(old_module_name)}", "test/integration/#{module_name_for_path(new_module_name)}" Dir.glob("test/integration/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No integration tests found in test/integration for #{old_version}" end end when :rspec if File.exists? "spec/controllers/#{module_name_for_path(old_module_name)}" log "Copying all files from spec/controllers/#{module_name_for_path(old_module_name)} to spec/controllers/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "spec/controllers/#{module_name_for_path(old_module_name)}", "spec/controllers/#{module_name_for_path(new_module_name)}" Dir.glob("spec/controllers/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No controller specs found in spec/controllers for #{old_version}" end if File.exists? "spec/requests/#{module_name_for_path(old_module_name)}" log "Copying all files from spec/requests/#{module_name_for_path(old_module_name)} to spec/requests/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "spec/requests/#{module_name_for_path(old_module_name)}", "spec/requests/#{module_name_for_path(new_module_name)}" Dir.glob("spec/requests/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No request specs found in spec/requests for #{old_version}" end else say "Unsupported test_framework: #{Versionist.configuration.configured_test_framework}" end end end def copy_presenters in_root do if File.exists? "app/presenters/#{module_name_for_path(old_module_name)}" log "Copying all files from app/presenters/#{module_name_for_path(old_module_name)} to app/presenters/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "app/presenters/#{module_name_for_path(old_module_name)}", "app/presenters/#{module_name_for_path(new_module_name)}" Dir.glob("app/presenters/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No presenters found in app/presenters for #{old_version}" end end end def copy_presenter_tests in_root do case Versionist.configuration.configured_test_framework when :test_unit if File.exists? "test/presenters/#{module_name_for_path(old_module_name)}" log "Copying all files from test/presenters/#{module_name_for_path(old_module_name)} to test/presenters/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "test/presenters/#{module_name_for_path(old_module_name)}", "test/presenters/#{module_name_for_path(new_module_name)}" Dir.glob("test/presenters/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No presenter tests found in test/presenters for #{old_version}" end when :rspec if File.exists? "spec/presenters/#{module_name_for_path(old_module_name)}" log "Copying all files from spec/presenters/#{module_name_for_path(old_module_name)} to spec/presenters/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "spec/presenters/#{module_name_for_path(old_module_name)}", "spec/presenters/#{module_name_for_path(new_module_name)}" Dir.glob("spec/presenters/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No presenter specs found in spec/presenters for #{old_version}" end else say "Unsupported test_framework: #{Versionist.configuration.configured_test_framework}" end end end def copy_helpers in_root do if File.exists? "app/helpers/#{module_name_for_path(old_module_name)}" log "Copying all files from app/helpers/#{module_name_for_path(old_module_name)} to app/helpers/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "app/helpers/#{module_name_for_path(old_module_name)}", "app/helpers/#{module_name_for_path(new_module_name)}" Dir.glob("app/helpers/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No helpers found in app/helpers for #{old_version}" end end end def copy_helper_tests in_root do case Versionist.configuration.configured_test_framework when :test_unit if File.exists? "test/helpers/#{module_name_for_path(old_module_name)}" log "Copying all files from test/helpers/#{module_name_for_path(old_module_name)} to test/helpers/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "test/helpers/#{module_name_for_path(old_module_name)}", "test/helpers/#{module_name_for_path(new_module_name)}" Dir.glob("test/helpers/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No helper tests found in test/helpers for #{old_version}" end when :rspec if File.exists? "spec/helpers/#{module_name_for_path(old_module_name)}" log "Copying all files from spec/helpers/#{module_name_for_path(old_module_name)} to spec/helpers/#{module_name_for_path(new_module_name)}" FileUtils.cp_r "spec/helpers/#{module_name_for_path(old_module_name)}", "spec/helpers/#{module_name_for_path(new_module_name)}" Dir.glob("spec/helpers/#{module_name_for_path(new_module_name)}/*.rb").each do |f| text = File.read(f) File.open(f, 'w') {|f| f << text.gsub(/#{old_module_name}/, new_module_name)} end else say "No helper specs found in spec/helpers for #{old_version}" end else say "Unsupported test_framework: #{Versionist.configuration.configured_test_framework}" end end end def copy_documentation in_root do if File.exists? "public/docs/#{old_version}" log "Copying all files from public/docs/#{old_version} to public/docs/#{new_version}" FileUtils.cp_r "public/docs/#{old_version}/.", "public/docs/#{new_version}" else say "No documentation found in public/docs for #{old_version}" end end end end end versionist-2.0.1/lib/generators/versionist/copy_api_version/USAGE0000644000004100000410000000170213516730105025233 0ustar www-datawww-dataDescription: Copies an existing API version to a new API version. Example: rails generate versionist:copy_api_version v2.0.0 V2_0_0 v3.0.0 V3_0_0 This will do the following: route api_version(:module => "V3__0__0", :header=>"Accept", :value=>"application/vnd.mycompany.com-v3.0.0") do end Copying all files from app/controllers/v2_0_0 to app/controllers/v3_0_0 Copying all files from spec/controllers/v2_0_0 to spec/controllers/v3_0_0 Copying all files from app/presenters/v2_0_0 to app/presenters/v3_0_0 Copying all files from spec/presenters/v2_0_0 to spec/presenters/v3_0_0 Copying all files from public/docs/v2.0.0 to public/docs/v3.0.0 Note: routes can only be copied with MRI Ruby 1.9 and above, as this feature relies on Ripper which is only available in stdlib in MRI Ruby 1.9 and above. Outside of routes copying, the other copy steps will work just fine in Ruby 1.8 and other non-MRI Ruby implementations. versionist-2.0.1/lib/generators/versionist/new_api_version/0000755000004100000410000000000013516730105024263 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/new_api_version/templates/0000755000004100000410000000000013516730105026261 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_presenter_test.rb0000644000004100000410000000026113516730105032645 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::BasePresenterTest < Test::Unit::TestCase # Replace this with your real tests. test "the truth" do assert true end end versionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_controller.rb0000644000004100000410000000010513516730105031757 0ustar www-datawww-dataclass <%= module_name %>::BaseController < ApplicationController end ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootversionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_controller_integration_test.rbversionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_controller_integration_tes0000644000004100000410000000027513516730105034643 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::BaseControllerTest < ActionDispatch::IntegrationTest # Replace this with your real tests. test "the truth" do assert true end end versionist-2.0.1/lib/generators/versionist/new_api_version/templates/docs_style.rb0000644000004100000410000000037713516730105030765 0ustar www-datawww-databody {margin: 0; background-color: #fff; color: #000; font-family: Arial,sans-serif;} content {margin-left: 200px;} content h1 {text-align: center;} operations {float: left; width: 200px; border-right: 1px solid #ccc;} operations h3 {text-align: center;} versionist-2.0.1/lib/generators/versionist/new_api_version/templates/docs_index.rb0000644000004100000410000000064313516730105030730 0ustar www-datawww-data Documentation for <%= version%>

API Operations

Documentation for <%= version%>

versionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_presenter.rb0000644000004100000410000000005413516730105031606 0ustar www-datawww-dataclass <%= module_name %>::BasePresenter end versionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_presenter_spec.rb0000644000004100000410000000013113516730105032614 0ustar www-datawww-datarequire '<%= @rspec_require_file %>' describe <%= module_name %>::BasePresenter do end ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootversionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_controller_functional_test.rbversionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_controller_functional_test0000644000004100000410000000027013516730105034641 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::BaseControllerTest < ActionController::TestCase # Replace this with your real tests. test "the truth" do assert true end end versionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_controller_spec.rb0000644000004100000410000000013213516730105032771 0ustar www-datawww-datarequire '<%= @rspec_require_file %>' describe <%= module_name %>::BaseController do end versionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_presenter_test_rails_5.rb0000644000004100000410000000026413516730105034266 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::BasePresenterTest < ActiveSupport::TestCase # Replace this with your real tests. test "the truth" do assert true end end ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootversionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_controller_functional_test_rails_5.rbversionist-2.0.1/lib/generators/versionist/new_api_version/templates/base_controller_functional_test0000644000004100000410000000027513516730105034646 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::BaseControllerTest < ActionDispatch::IntegrationTest # Replace this with your real tests. test "the truth" do assert true end end versionist-2.0.1/lib/generators/versionist/new_api_version/new_api_version_generator.rb0000644000004100000410000001524113516730105032050 0ustar www-datawww-datamodule Versionist class NewApiVersionGenerator < Rails::Generators::Base include InflectorFixes include RspecHelper desc "creates the infrastructure for a new API version" source_root File.expand_path('../templates', __FILE__) argument :version, :type => :string argument :module_name, :type => :string class_option :default, :type => :boolean class_option :header, :type => :hash, :group => :header class_option :parameter, :type => :hash, :group => :parameter class_option :path, :type => :hash, :group => :path class_option :defaults, :type => :hash, :group => :defaults def verify_options raise "Must specify at least one versioning strategy option" if !['header', 'parameter', 'path'].any? {|strategy| options.has_key?(strategy)} if options.has_key?("header") raise "Must specify name and value for header versioning strategy" if !options["header"].has_key?("name") || !options["header"].has_key?("value") end if options.has_key?("parameter") raise "Must specify name and value for parameter versioning strategy" if !options["parameter"].has_key?("name") || !options["parameter"].has_key?("value") end if options.has_key?("path") raise "Must specify value for path versioning strategy" if !options["path"].has_key?("value") end end def add_routes in_root do api_version_block = /api_version.*:module\s*(=>|:)\s*("|')#{module_name_for_route(module_name)}("|')/ matching_version_blocks = File.readlines("config/routes.rb").grep(api_version_block) raise "API version already exists in config/routes.rb" if !matching_version_blocks.empty? route_string = "api_version(:module => \"#{module_name_for_route(module_name)}\"" ['header', 'parameter', 'path'].each do |versioning_strategy| if options.has_key?(versioning_strategy) options[versioning_strategy].symbolize_keys! route_string << ", :#{versioning_strategy} => {#{options[versioning_strategy].to_s.gsub(/[\{\}]/, '').gsub('=>', ' => ')}}" end end if options.has_key?('defaults') options['defaults'].symbolize_keys! route_string << ", :defaults => {#{options['defaults'].to_s.gsub(/[\{\}]/, '').gsub('=>', ' => ')}}" end if options.has_key?('default') route_string << ", :default => true" end route_string << ") do\n end" route route_string end end def add_controller_base in_root do empty_directory "app/controllers/#{module_name_for_path(module_name)}" template 'base_controller.rb', File.join("app", "controllers", "#{module_name_for_path(module_name)}", "base_controller.rb") end end # due to the inflector quirks we can't use hook_for :test_framework def add_controller_base_tests in_root do case Versionist.configuration.configured_test_framework when :test_unit empty_directory "test/#{Versionist.test_path}/#{module_name_for_path(module_name)}" empty_directory "test/integration/#{module_name_for_path(module_name)}" if Versionist.older_than_rails_5? template 'base_controller_integration_test.rb', File.join("test", "integration", "#{module_name_for_path(module_name)}", "base_controller_test.rb") template 'base_controller_functional_test.rb', File.join("test", "#{Versionist.test_path}", "#{module_name_for_path(module_name)}", "base_controller_test.rb") else template 'base_controller_functional_test_rails_5.rb', File.join("test", "#{Versionist.test_path}", "#{module_name_for_path(module_name)}", "base_controller_test_rails_5.rb") end when :rspec @rspec_require_file = rspec_helper_filename empty_directory "spec/controllers/#{module_name_for_path(module_name)}" template 'base_controller_spec.rb', File.join("spec", "controllers", "#{module_name_for_path(module_name)}", "base_controller_spec.rb"), :assigns => { :rspec_require_file => @rspec_require_file } empty_directory "spec/requests/#{module_name_for_path(module_name)}" template 'base_controller_spec.rb', File.join("spec", "requests", "#{module_name_for_path(module_name)}", "base_controller_spec.rb"), :assigns => { :rspec_require_file => @rspec_require_file } else say "Unsupported test_framework: #{Versionist.configuration.configured_test_framework}" end end end def add_presenters_base in_root do empty_directory "app/presenters/#{module_name_for_path(module_name)}" template 'base_presenter.rb', File.join("app", "presenters", "#{module_name_for_path(module_name)}", "base_presenter.rb") end end def add_presenter_test in_root do case Versionist.configuration.configured_test_framework when :test_unit empty_directory "test/presenters/#{module_name_for_path(module_name)}" if Versionist.older_than_rails_5? template 'base_presenter_test.rb', File.join("test", "presenters", "#{module_name_for_path(module_name)}", "base_presenter_test.rb") else template 'base_presenter_test_rails_5.rb', File.join("test", "presenters", "#{module_name_for_path(module_name)}", "base_presenter_test_rails_5.rb") end when :rspec @rspec_require_file = rspec_helper_filename empty_directory "spec/presenters/#{module_name_for_path(module_name)}" template 'base_presenter_spec.rb', File.join("spec", "presenters", "#{module_name_for_path(module_name)}", "base_presenter_spec.rb"), :assigns => { :rspec_require_file => @rspec_require_file } else say "Unsupported test_framework: #{Versionist.configuration.configured_test_framework}" end end end def add_helpers_dir in_root do empty_directory "app/helpers/#{module_name_for_path(module_name)}" end end def add_helpers_test_dir in_root do case Versionist.configuration.configured_test_framework when :test_unit empty_directory "test/helpers/#{module_name_for_path(module_name)}" when :rspec empty_directory "spec/helpers/#{module_name_for_path(module_name)}" else say "Unsupported test_framework: #{Versionist.configuration.configured_test_framework}" end end end def add_documentation_base in_root do empty_directory "public/docs/#{version}" template 'docs_index.rb', File.join("public", "docs", "#{version}", "index.html") template 'docs_style.rb', File.join("public", "docs", "#{version}", "style.css") end end end end versionist-2.0.1/lib/generators/versionist/new_api_version/USAGE0000644000004100000410000000145013516730105025052 0ustar www-datawww-dataDescription: Creates the infrastructure for a new API version. Example: rails generate versionist:new_api_version v2.0.0 V2_0_0 header:Accept value:application/vnd.mycompany.com-v2.0.0 This will create: route api_version(:module => "V2__0__0", :header=>"Accept", :value=>"application/vnd.mycompany.com-v2.0.0") do end create app/controllers/v2_0_0 create app/controllers/v2_0_0/base_controller.rb create app/presenters/v2_0_0 create app/presenters/v2_0_0/base_presenter.rb create public/docs/v2.0.0 create public/docs/v2.0.0/index.html create public/docs/v2.0.0/style.css In addition this will create tests for base_controller.rb and base_presenter.rb using the test_framework currently configured in your Rails app. versionist-2.0.1/lib/generators/versionist/new_controller/0000755000004100000410000000000013516730105024130 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/new_controller/new_controller_generator.rb0000644000004100000410000000554413516730105031567 0ustar www-datawww-datamodule Versionist class NewControllerGenerator < Rails::Generators::NamedBase include InflectorFixes include RspecHelper desc "creates a new controller for an existing API version" source_root File.expand_path('../templates', __FILE__) argument :module_name, :type => :string def new_controller in_root do raise "API module namespace #{module_name} doesn't exist. Please run \'rails generate versionist:new_api_version\' generator first" if !File.exists?("app/controllers/#{module_name_for_path(module_name)}") template 'new_controller.rb', File.join("app", "controllers", "#{module_name_for_path(module_name)}", "#{file_name}_controller.rb") api_version_block = /api_version.*:?module\s*(=>|:)\s*("|')#{module_name_for_route(module_name)}("|')/ new_route = " resources :#{file_name}\n" matching_version_blocks = File.readlines("config/routes.rb").grep(api_version_block) if matching_version_blocks.empty? raise "API version doesn't exist in config/routes.rb. Please run \'rails generate versionist:new_api_version\' generator first" elsif matching_version_blocks.size > 1 raise "API version is duplicated in config/routes.rb" else version_block = matching_version_blocks.first inject_into_file "config/routes.rb", "#{new_route}", {:after => version_block, :verbose => false} end end end # due to the inflector quirks we can't use hook_for :test_framework def new_controller_tests in_root do case Versionist.configuration.configured_test_framework when :test_unit if Versionist.older_than_rails_5? template 'new_controller_integration_test.rb', File.join("test", "integration", "#{module_name_for_path(module_name)}", "#{file_name}_controller_test.rb") template 'new_controller_functional_test.rb', File.join("test", "#{Versionist.test_path}", "#{module_name_for_path(module_name)}", "#{file_name}_controller_test.rb") else template 'new_controller_functional_test_rails_5.rb', File.join("test", "#{Versionist.test_path}", "#{module_name_for_path(module_name)}", "#{file_name}_controller_test_rails_5.rb") end when :rspec @rspec_require_file = rspec_helper_filename template 'new_controller_spec.rb', File.join("spec", "controllers", "#{module_name_for_path(module_name)}", "#{file_name}_controller_spec.rb"), :assigns => { :rspec_require_file => @rspec_require_file } template 'new_controller_spec.rb', File.join("spec", "requests", "#{module_name_for_path(module_name)}", "#{file_name}_controller_spec.rb"), :assigns => { :rspec_require_file => @rspec_require_file } else say "Unsupported test_framework: #{Versionist.configuration.configured_test_framework}" end end end end end versionist-2.0.1/lib/generators/versionist/new_controller/templates/0000755000004100000410000000000013516730105026126 5ustar www-datawww-dataversionist-2.0.1/lib/generators/versionist/new_controller/templates/new_controller_spec.rb0000644000004100000410000000014613516730105032522 0ustar www-datawww-datarequire '<%= @rspec_require_file %>' describe <%= module_name %>::<%= class_name%>Controller do end ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootversionist-2.0.1/lib/generators/versionist/new_controller/templates/new_controller_integration_test.rbversionist-2.0.1/lib/generators/versionist/new_controller/templates/new_controller_integration_test.0000644000004100000410000000031213516730105034621 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::<%= class_name%>ControllerTest < ActionDispatch::IntegrationTest # Replace this with your real tests. test "the truth" do assert true end end ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootversionist-2.0.1/lib/generators/versionist/new_controller/templates/new_controller_functional_test.rbversionist-2.0.1/lib/generators/versionist/new_controller/templates/new_controller_functional_test.r0000644000004100000410000000030513516730105034624 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::<%= class_name%>ControllerTest < ActionController::TestCase # Replace this with your real tests. test "the truth" do assert true end end versionist-2.0.1/lib/generators/versionist/new_controller/templates/new_controller.rb0000644000004100000410000000013613516730105031507 0ustar www-datawww-dataclass <%= module_name %>::<%= class_name%>Controller < <%= module_name %>::BaseController end ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootversionist-2.0.1/lib/generators/versionist/new_controller/templates/new_controller_functional_test_rails_5.rbversionist-2.0.1/lib/generators/versionist/new_controller/templates/new_controller_functional_test_r0000644000004100000410000000031213516730105034703 0ustar www-datawww-datarequire 'test_helper' class <%= module_name %>::<%= class_name%>ControllerTest < ActionDispatch::IntegrationTest # Replace this with your real tests. test "the truth" do assert true end end versionist-2.0.1/lib/generators/versionist/new_controller/USAGE0000644000004100000410000000056213516730105024722 0ustar www-datawww-dataDescription: Creates a new controller class with the given name under the given module namespace Example: rails generate versionist:new_controller test V2_0_0 This will create: app/controllers/V2_0_0/test_controller.rb In addition this will create a test for the new controller using the test_framework currently configured in your Rails app. versionist-2.0.1/lib/generators/versionist/rspec_helper.rb0000644000004100000410000000047213516730105024077 0ustar www-datawww-datamodule Versionist module RspecHelper # Gets the name of the helper file to require in spec files # Accounting for rspec-rails 2 vs rspec-rails 3 def rspec_helper_filename if File.exists? "spec/rails_helper.rb" "rails_helper" else "spec_helper" end end end end versionist-2.0.1/lib/versionist.rb0000644000004100000410000000213013516730105017244 0ustar www-datawww-datarequire 'active_support/dependencies/autoload' module Versionist extend ActiveSupport::Autoload autoload :Configuration autoload :InflectorFixes, "generators/versionist/inflector_fixes" autoload :RspecHelper, "generators/versionist/rspec_helper" autoload :CopyApiVersionGenerator, "generators/versionist/copy_api_version/copy_api_version_generator" autoload :NewApiVersionGenerator, "generators/versionist/new_api_version/new_api_version_generator" autoload :NewControllerGenerator, "generators/versionist/new_controller/new_controller_generator" autoload :NewPresenterGenerator, "generators/versionist/new_presenter/new_presenter_generator" autoload :VersioningStrategy, "versionist/versioning_strategy" autoload :Middleware autoload :Routing def self.configuration @@configuration ||= Configuration.new end def self.older_than_rails_5? defined?(Rails) && Rails.version.to_i < 5 end def self.test_path return "test/functional" if older_than_rails_5? "test/controllers" end end require 'versionist/railtie' if defined?(Rails) && Rails::VERSION::MAJOR >= 3 versionist-2.0.1/lib/versionist/0000755000004100000410000000000013516730105016723 5ustar www-datawww-dataversionist-2.0.1/lib/versionist/version.rb0000644000004100000410000000005213516730105020732 0ustar www-datawww-datamodule Versionist VERSION = '2.0.1' end versionist-2.0.1/lib/versionist/railtie.rb0000644000004100000410000000107213516730105020701 0ustar www-datawww-datarequire 'rails/railtie' module Versionist class Railtie < Rails::Railtie config.versionist = ActiveSupport::OrderedOptions.new initializer 'versionist.configure' do |app| ActionDispatch::Routing::Mapper.send :include, Versionist::Routing end config.app_middleware.use Versionist::Middleware config.after_initialize do generators = config.respond_to?(:app_generators) ? config.app_generators : config.generators Versionist.configuration.configured_test_framework = generators.options[:rails][:test_framework] end end end versionist-2.0.1/lib/versionist/routing.rb0000644000004100000410000000776013516730105020751 0ustar www-datawww-datarequire 'active_support/core_ext/hash/keys' module Versionist module Routing # Allows you to constrain routes to specific versions of your api using versioning strategies. # Supported formats: # # HTTP Header # api_version(:module => "V1", :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}}) # # Path # api_version(:module => "V1", :path => {:value => "v1"}}) # # Request Parameter # api_version(:module => "V1", :parameter => {:name => "version", :value => "1"}}) # # Specifying default version: # api_version(:module => "V1", :default => true, :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}}) # # Multiple Strategies per version # api_version(:module => "V1", :header => {:name => "Accept", :value => "application/vnd.mycompany.com; version=1"}, :path => {:value => "v1"}) def api_version(config, &block) raise ArgumentError, "you must pass a configuration Hash to api_version" if config.nil? || !config.is_a?(Hash) config.symbolize_keys! raise ArgumentError, "you must specify :header, :path, or :parameter in configuration Hash passed to api_version" if !config.has_key?(:header) && !config.has_key?(:path) && !config.has_key?(:parameter) [:header, :path, :parameter].each do |s| raise ArgumentError, "#{s} key in configuration Hash passed to api_version must point to a Hash" if config.has_key?(s) && !config[s].is_a?(Hash) end raise ArgumentError, "you must specify :module in configuration Hash passed to api_version" if !config.has_key?(:module) raise ArgumentError, ":defaults must be a Hash" if config.has_key?(:defaults) && !config[:defaults].is_a?(Hash) rails_quirks(config, &block) configure_header(config, &block) if config.has_key?(:header) configure_path(config, &block) if config.has_key?(:path) configure_parameter(config, &block) if config.has_key?(:parameter) configure_default(config, &block) if config.has_key?(:default) && config[:default] end private def configure_header(config, &block) header = Versionist::VersioningStrategy::Header.new(config) route_hash = {:module => config[:module], :constraints => header} route_hash.merge!({:defaults => config[:defaults]}) if config.has_key?(:defaults) scope(route_hash, &block) end def configure_path(config, &block) config[:path][:value].slice!(0) if config[:path][:value] =~ /^\// path = Versionist::VersioningStrategy::Path.new(config) # Use the :as option and strip out non-word characters from the path to avoid this: # https://github.com/rails/rails/issues/3224 route_hash = {:module => config[:module], :as => config[:path][:value].gsub(/\W/, '_')} route_hash.merge!({:defaults => config[:defaults]}) if config.has_key?(:defaults) namespace(config[:path][:value], route_hash, &block) end def configure_parameter(config, &block) parameter = Versionist::VersioningStrategy::Parameter.new(config) route_hash = {:module => config[:module], :constraints => parameter, :as => config[:parameter][:value].gsub(/\W/, '_')} route_hash.merge!({:defaults => config[:defaults]}) if config.has_key?(:defaults) scope(route_hash, &block) end def configure_default(config, &block) default = Versionist::VersioningStrategy::Default.new(config) route_hash = {:module => config[:module], :constraints => default, :as => 'default'} route_hash.merge!({:defaults => config[:defaults]}) if config.has_key?(:defaults) scope(route_hash, &block) end # deals with quirks in routing among the various Rails versions def rails_quirks(config, &block) # Rails 4 no longer allows constant syntax in routing. # https://github.com/bploetz/versionist/issues/39 # call underscore on the module so it adheres to this convention config[:module] = config[:module].underscore if Rails::VERSION::MAJOR >= 4 end end end versionist-2.0.1/lib/versionist/configuration.rb0000644000004100000410000000117413516730105022122 0ustar www-datawww-datamodule Versionist class Configuration attr_accessor :versioning_strategies attr_accessor :default_version attr_accessor :header_versions attr_accessor :parameter_versions attr_accessor :path_versions attr_accessor :configured_test_framework def initialize @versioning_strategies ||= Array.new @header_versions ||= Array.new @parameter_versions ||= Array.new @path_versions ||= Array.new end def clear! @versioning_strategies.clear @default_version = nil @header_versions.clear @parameter_versions.clear @path_versions.clear end end end versionist-2.0.1/lib/versionist/versioning_strategy/0000755000004100000410000000000013516730105023030 5ustar www-datawww-dataversionist-2.0.1/lib/versionist/versioning_strategy/default.rb0000644000004100000410000000223413516730105025002 0ustar www-datawww-datamodule Versionist module VersioningStrategy # Implements the default version handling strategy. class Default < Base attr_accessor :strategies attr_accessor :module def initialize(config) super @module = config[:module] raise ArgumentError, "[VERSIONIST] attempt to set more than one default api version" if !Versionist.configuration.default_version.nil? && Versionist.configuration.default_version != self Versionist.configuration.default_version = self end def matches?(request) !header_matches?(request) && !parameter_matches?(request) end def ==(other) super return false if !other.is_a?(Versionist::VersioningStrategy::Default) return self.module == other.module end private def header_matches?(request) Versionist.configuration.header_versions && Versionist.configuration.header_versions.any? {|v| v.matches?(request)} end def parameter_matches?(request) Versionist.configuration.parameter_versions && Versionist.configuration.parameter_versions.any? {|v| v.matches?(request)} end end end end versionist-2.0.1/lib/versionist/versioning_strategy/header.rb0000644000004100000410000000375613516730105024620 0ustar www-datawww-datamodule Versionist module VersioningStrategy # Implements the header versioning strategy. class Header < Base # Creates a new Header VersioningStrategy object. config must contain the following keys: # - :header the header hash to inspect def initialize(config) super raise ArgumentError, "you must specify :name in the :header configuration Hash" if !config[:header].has_key?(:name) raise ArgumentError, "you must specify :value in the :header configuration Hash" if !config[:header].has_key?(:value) raise ArgumentError, "a header :name of 'version' will clash with the built in rack header \"HTTP_VERSION\". You must use a different header name" if config[:header][:name].downcase == "version" Versionist.configuration.header_versions << self if !Versionist.configuration.header_versions.include?(self) end def matches?(request) header_string = request.headers[config[:header][:name]].to_s if !header_string.blank? potential_matches = Versionist.configuration.header_versions.select {|hv| header_string.include?(hv.config[:header][:value])} if !potential_matches.empty? if potential_matches.include?(self) if potential_matches.size == 1 return true else # when finding multiple potential matches, the match with the longest value wins # (i.e. v2.1 trumps v2), as one is a subset of the other longest = potential_matches.max {|a,b| a.config[:header][:value].length <=> b.config[:header][:value].length} return longest == self end end end end false end def ==(other) super return false if !other.is_a?(Versionist::VersioningStrategy::Header) return self.config[:header][:name] == other.config[:header][:name] && self.config[:header][:value] == other.config[:header][:value] end end end end versionist-2.0.1/lib/versionist/versioning_strategy/base.rb0000644000004100000410000000120613516730105024266 0ustar www-datawww-datarequire 'active_support/core_ext/hash/keys' module Versionist module VersioningStrategy class Base attr_reader :config def initialize(config={}) raise ArgumentError, "you must pass a configuration Hash" if config.nil? || !config.is_a?(Hash) @config = config @config.symbolize_keys! Versionist.configuration.versioning_strategies << self if !Versionist.configuration.versioning_strategies.include?(self) end def ==(other) return false if other.nil? || !other.is_a?(Versionist::VersioningStrategy::Base) return self.config == other.config end end end end versionist-2.0.1/lib/versionist/versioning_strategy/parameter.rb0000644000004100000410000000227413516730105025342 0ustar www-datawww-datamodule Versionist module VersioningStrategy # Implements the parameter versioning strategy. class Parameter < Base # Creates a new Parameter VersioningStrategy object. config must contain the following keys: # - :parameter the parameter hash to inspect def initialize(config) super raise ArgumentError, "you must specify :name in the :parameter configuration Hash" if !config[:parameter].has_key?(:name) raise ArgumentError, "you must specify :value in the :parameter configuration Hash" if !config[:parameter].has_key?(:value) Versionist.configuration.parameter_versions << self if !Versionist.configuration.parameter_versions.include?(self) end def matches?(request) parameter_string = request.params[config[:parameter][:name]].to_s return !parameter_string.blank? && parameter_string == config[:parameter][:value] end def ==(other) super return false if !other.is_a?(Versionist::VersioningStrategy::Parameter) return self.config[:parameter][:name] == other.config[:parameter][:name] && self.config[:parameter][:value] == other.config[:parameter][:value] end end end end versionist-2.0.1/lib/versionist/versioning_strategy/path.rb0000644000004100000410000000147313516730105024316 0ustar www-datawww-datamodule Versionist module VersioningStrategy # Implements the path versioning strategy. It expects the following path format: # GET //... class Path < Base # Creates a new Path VersioningStrategy object. config must contain the following keys: # - :path the path prefix containing the version def initialize(config) super raise ArgumentError, "you must specify :value in the :path configuration Hash" if !config[:path].has_key?(:value) Versionist.configuration.path_versions << self if !Versionist.configuration.path_versions.include?(self) end def ==(other) super return false if !other.is_a?(Versionist::VersioningStrategy::Path) return self.config[:path][:value] == other.config[:path][:value] end end end end versionist-2.0.1/lib/versionist/versioning_strategy.rb0000644000004100000410000000062213516730105023355 0ustar www-datawww-datamodule Versionist module VersioningStrategy extend ActiveSupport::Autoload autoload :Base, 'versionist/versioning_strategy/base' autoload :Header, 'versionist/versioning_strategy/header' autoload :Path, 'versionist/versioning_strategy/path' autoload :Parameter, 'versionist/versioning_strategy/parameter' autoload :Default, 'versionist/versioning_strategy/default' end end versionist-2.0.1/lib/versionist/middleware.rb0000644000004100000410000000312513516730105021366 0ustar www-datawww-datamodule Versionist # When your routes don't include an explicit format in the URL (i.e. `match 'foos.(:format)' => foos#index`), # Rails inspects the `Accept` header to determine the requested format. Since an `Accept` header can have multiple values, # Rails uses the first one present to determine the format. If your custom version header happens to be the first value # in the `Accept` header, it would incorrectly be interpretted as the format. This middleware moves your custom version header # (if found) to the end of the `Accept` header so as to not interfere with this format logic in Rails. class Middleware ACCEPT = "Accept" HTTP_ACCEPT = "HTTP_ACCEPT" def initialize(app) @app = app end def call(env) dup._call(env) end def _call(env) request = ::Rack::Request.new(env) potential_matches = Versionist.configuration.header_versions.select {|hv| hv.config[:header][:name] == ACCEPT && env[HTTP_ACCEPT].try(:include?, hv.config[:header][:value])} if !potential_matches.empty? strategy = potential_matches.max {|a,b| a.config[:header][:value].length <=> b.config[:header][:value].length} end if !strategy.nil? entries = env[HTTP_ACCEPT].split(',') index = -1 entries.each_with_index do |e, i| e.strip! index = i if e == strategy.config[:header][:value] end if (index != -1) version = entries.delete_at(index) entries << version end env[HTTP_ACCEPT] = entries.join(", ") end @app.call(env) end end end versionist-2.0.1/versionist.gemspec0000644000004100000410000001062113516730105017522 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: versionist 2.0.1 ruby lib Gem::Specification.new do |s| s.name = "versionist".freeze s.version = "2.0.1" s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Brian Ploetz".freeze] s.date = "2019-07-22" s.description = "A plugin for versioning Rails based RESTful APIs.".freeze s.files = ["lib/generators/versionist/copy_api_version/USAGE".freeze, "lib/generators/versionist/copy_api_version/copy_api_version_generator.rb".freeze, "lib/generators/versionist/inflector_fixes.rb".freeze, "lib/generators/versionist/new_api_version/USAGE".freeze, "lib/generators/versionist/new_api_version/new_api_version_generator.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller_functional_test.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller_functional_test_rails_5.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller_integration_test.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_controller_spec.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_presenter.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_presenter_spec.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_presenter_test.rb".freeze, "lib/generators/versionist/new_api_version/templates/base_presenter_test_rails_5.rb".freeze, "lib/generators/versionist/new_api_version/templates/docs_index.rb".freeze, "lib/generators/versionist/new_api_version/templates/docs_style.rb".freeze, "lib/generators/versionist/new_controller/USAGE".freeze, "lib/generators/versionist/new_controller/new_controller_generator.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller_functional_test.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller_functional_test_rails_5.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller_integration_test.rb".freeze, "lib/generators/versionist/new_controller/templates/new_controller_spec.rb".freeze, "lib/generators/versionist/new_presenter/USAGE".freeze, "lib/generators/versionist/new_presenter/new_presenter_generator.rb".freeze, "lib/generators/versionist/new_presenter/templates/new_presenter.rb".freeze, "lib/generators/versionist/new_presenter/templates/new_presenter_spec.rb".freeze, "lib/generators/versionist/new_presenter/templates/new_presenter_test.rb".freeze, "lib/generators/versionist/new_presenter/templates/new_presenter_test_rails_5.rb".freeze, "lib/generators/versionist/rspec_helper.rb".freeze, "lib/versionist.rb".freeze, "lib/versionist/configuration.rb".freeze, "lib/versionist/middleware.rb".freeze, "lib/versionist/railtie.rb".freeze, "lib/versionist/routing.rb".freeze, "lib/versionist/version.rb".freeze, "lib/versionist/versioning_strategy.rb".freeze, "lib/versionist/versioning_strategy/base.rb".freeze, "lib/versionist/versioning_strategy/default.rb".freeze, "lib/versionist/versioning_strategy/header.rb".freeze, "lib/versionist/versioning_strategy/parameter.rb".freeze, "lib/versionist/versioning_strategy/path.rb".freeze] s.homepage = "https://github.com/bploetz/versionist".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--charset=UTF-8".freeze] s.rubygems_version = "2.5.2.1".freeze s.summary = "versionist-2.0.1".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q.freeze, [">= 3"]) s.add_runtime_dependency(%q.freeze, [">= 3"]) s.add_runtime_dependency(%q.freeze, ["~> 0.9.20"]) else s.add_dependency(%q.freeze, [">= 3"]) s.add_dependency(%q.freeze, [">= 3"]) s.add_dependency(%q.freeze, ["~> 0.9.20"]) end else s.add_dependency(%q.freeze, [">= 3"]) s.add_dependency(%q.freeze, [">= 3"]) s.add_dependency(%q.freeze, ["~> 0.9.20"]) end end