Commit 0b054562 by cuong.tran

Merge branch 'release/v2.7.0'

parents d878a5b7 bee8f380
sudo: false
language: ruby language: ruby
rvm: rvm:
- 1.9.3 - 1.9.3
- 2.0 - 2.0
- 2.1 - 2.1
- 2.2 - 2.2
- 2.3.0-preview1
before_install: before_install:
- rvm @global do gem install bundler - rvm @global do gem install bundler
== 2.7.0
See https://github.com/ctran/annotate_models/releases/tag/v2.7.0
== 2.6.9 == 2.6.9
* Support foreigh key (#241) * Support foreigh key (#241)
* Check if model has skip tag in annotate_model_file (#167) * Check if model has skip tag in annotate_model_file (#167)
......
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'rake', '>= 0.8.7', :require => false gem 'rake', '>= 10.4.2', :require => false
gem 'activerecord', '>= 2.3.0', :require => false gem 'activerecord', '>= 4.2.5', :require => false
group :development do group :development do
gem 'mg', :require => false gem 'mg', :require => false
...@@ -23,6 +23,6 @@ group :development, :test do ...@@ -23,6 +23,6 @@ group :development, :test do
end end
group :test do group :test do
gem 'wrong', '>=0.6.2', :require => false gem 'wrong', :require => false
gem 'files', '>=0.2.1', :require => false gem 'files', :require => false
end end
...@@ -51,7 +51,7 @@ Also, if you pass the -r option, it'll annotate routes.rb with the output of ...@@ -51,7 +51,7 @@ Also, if you pass the -r option, it'll annotate routes.rb with the output of
Into Gemfile from rubygems.org: Into Gemfile from rubygems.org:
gem 'annotate', '~> 2.6.6' gem 'annotate'
Into Gemfile from Github: Into Gemfile from Github:
...@@ -100,9 +100,7 @@ To remove routes.rb annotations: ...@@ -100,9 +100,7 @@ To remove routes.rb annotations:
annotate --routes --delete annotate --routes --delete
To automatically annotate every time you run +db:migrate+, either run +rails g annotate:install+ or add +Annotate.load_tasks+ to your `Rakefile`. See the [configuration in Rails](#configuration-in-rails) section for more info.
== Configuration
=== Usage Outside of Rails === Usage Outside of Rails
...@@ -112,7 +110,6 @@ or more +--model-dir+ options to inform annotate about the structure of your ...@@ -112,7 +110,6 @@ or more +--model-dir+ options to inform annotate about the structure of your
project and help it bootstrap and load the relevant code. project and help it bootstrap and load the relevant code.
== Configuration == Configuration
If you want to always skip annotations on a particular model, add this string If you want to always skip annotations on a particular model, add this string
...@@ -130,7 +127,13 @@ default options: ...@@ -130,7 +127,13 @@ default options:
Edit this file to control things like output format, where annotations are Edit this file to control things like output format, where annotations are
added (top or bottom of file), and in which artifacts. added (top or bottom of file), and in which artifacts.
== Rails Integration The generated rakefile +lib/tasks/auto_annotate_models.rake+ also contains
`Annotate.load_tasks`. This adds a few rake tasks which duplicate command-line
functionality:
rake annotate_models # Add schema information (as comments) to model and fixture files
rake annotate_routes # Adds the route map to routes.rb
rake remove_annotation # Remove schema information from model and fixture files
By default, once you've generated a configuration file, annotate will be By default, once you've generated a configuration file, annotate will be
executed whenever you run +rake db:migrate+ (but only in development mode). executed whenever you run +rake db:migrate+ (but only in development mode).
......
...@@ -27,13 +27,13 @@ Gem::Specification.new do |s| ...@@ -27,13 +27,13 @@ Gem::Specification.new do |s|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<rake>, ["~> 10.4"]) s.add_runtime_dependency(%q<rake>, ["~> 10.4"])
s.add_runtime_dependency(%q<activerecord>, [">= 3.2", "<= 4.3"]) s.add_runtime_dependency(%q<activerecord>, [">= 3.2", "< 6.0"])
else else
s.add_dependency(%q<rake>, ["~> 10.4"]) s.add_dependency(%q<rake>, ["~> 10.4"])
s.add_dependency(%q<activerecord>, [">= 3.2", "<= 4.3"]) s.add_dependency(%q<activerecord>, [">= 3.2", "< 6.0"])
end end
else else
s.add_dependency(%q<rake>, [">= 0.8.7"]) s.add_dependency(%q<rake>, [">= 0.8.7"])
s.add_dependency(%q<activerecord>, [">= 3.2", "<= 4.3"]) s.add_dependency(%q<activerecord>, [">= 3.2", "< 6.0"])
end end
end end
...@@ -18,18 +18,16 @@ require 'optparse' ...@@ -18,18 +18,16 @@ require 'optparse'
require 'annotate' require 'annotate'
Annotate.bootstrap_rake Annotate.bootstrap_rake
target = {
:klass => AnnotateModels,
:task => :do_annotations,
}
has_set_position = {} has_set_position = {}
target_action = :do_annotations
OptionParser.new do |opts| OptionParser.new do |opts|
opts.banner = "Usage: annotate [options] [model_file]*" opts.banner = "Usage: annotate [options] [model_file]*"
opts.on('-d', '--delete', opts.on('-d', '--delete',
"Remove annotations from all model files or the routes.rb file") do "Remove annotations from all model files or the routes.rb file") do
target[:task] = :remove_annotations target_action = :remove_annotations
end end
opts.on('-p', '--position [before|top|after|bottom]', ['before', 'top', 'after', 'bottom'], opts.on('-p', '--position [before|top|after|bottom]', ['before', 'top', 'after', 'bottom'],
...@@ -93,10 +91,7 @@ OptionParser.new do |opts| ...@@ -93,10 +91,7 @@ OptionParser.new do |opts|
opts.on('-r', '--routes', opts.on('-r', '--routes',
"Annotate routes.rb with the output of 'rake routes'") do "Annotate routes.rb with the output of 'rake routes'") do
target = { ENV['routes'] = 'true'
:klass => AnnotateRoutes,
:task => :do_annotations
}
end end
opts.on('-v', '--version', opts.on('-v', '--version',
...@@ -129,6 +124,11 @@ OptionParser.new do |opts| ...@@ -129,6 +124,11 @@ OptionParser.new do |opts|
ENV['model_dir'] = dir ENV['model_dir'] = dir
end end
opts.on('--root-dir dir',
"Annotate files stored within root dir projects, separate multiple dirs with comas") do |dir|
ENV['root_dir'] = dir
end
opts.on('--ignore-model-subdirects', opts.on('--ignore-model-subdirects',
"Ignore subdirectories of the models directory") do |dir| "Ignore subdirectories of the models directory") do |dir|
ENV['ignore_model_sub_dir'] = "yes" ENV['ignore_model_sub_dir'] = "yes"
...@@ -178,8 +178,18 @@ OptionParser.new do |opts| ...@@ -178,8 +178,18 @@ OptionParser.new do |opts|
ENV['ignore_columns'] = regex ENV['ignore_columns'] = regex
end end
opts.on('--hide-limit-column-types VALUES', "don't show limit for given column types, separated by comas (i.e., `integer,boolean,text`)" ) do |values|
ENV['hide_limit_column_types'] = "#{values}"
end
opts.on('--ignore-unknown-models', "don't display warnings for bad model files" ) do |values|
ENV['ignore_unknown_models'] = "true"
end
end.parse! end.parse!
options = Annotate.setup_options({ :is_rake => ENV['is_rake'] && !ENV['is_rake'].empty? }) options = Annotate.setup_options({ :is_rake => ENV['is_rake'] && !ENV['is_rake'].empty? })
Annotate.eager_load(options) Annotate.eager_load(options)
target[:klass].send(target[:task], options)
AnnotateModels.send(target_action, options) if Annotate.include_models?
AnnotateRoutes.send(target_action, options) if Annotate.include_routes?
...@@ -7,7 +7,7 @@ begin ...@@ -7,7 +7,7 @@ begin
# ActiveSupport 3.x... # ActiveSupport 3.x...
require 'active_support/hash_with_indifferent_access' require 'active_support/hash_with_indifferent_access'
require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/blank'
rescue Exception => e rescue Exception
# ActiveSupport 2.x... # ActiveSupport 2.x...
require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/blank' require 'active_support/core_ext/blank'
...@@ -27,32 +27,36 @@ module Annotate ...@@ -27,32 +27,36 @@ module Annotate
:exclude_fixtures, :exclude_factories, :ignore_model_sub_dir, :exclude_fixtures, :exclude_factories, :ignore_model_sub_dir,
:format_bare, :format_rdoc, :format_markdown, :sort, :force, :trace, :format_bare, :format_rdoc, :format_markdown, :sort, :force, :trace,
:timestamp, :exclude_serializers, :classified_sort, :show_foreign_keys, :timestamp, :exclude_serializers, :classified_sort, :show_foreign_keys,
:exclude_scaffolds, :exclude_controllers, :exclude_helpers, :ignore_unknown_models,
] ]
OTHER_OPTIONS=[ OTHER_OPTIONS=[
:ignore_columns :ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close, :wrapper, :routes,
:hide_limit_column_types,
] ]
PATH_OPTIONS=[ PATH_OPTIONS=[
:require, :model_dir :require, :model_dir, :root_dir
] ]
## ##
# Set default values that can be overridden via environment variables. # Set default values that can be overridden via environment variables.
# #
def self.set_defaults(options = {}) def self.set_defaults(options = {})
return if(@has_set_defaults) return if(@has_set_defaults)
@has_set_defaults = true @has_set_defaults = true
options = HashWithIndifferentAccess.new(options) options = HashWithIndifferentAccess.new(options)
[POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS, OTHER_OPTIONS].flatten.each do |key| [POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS, OTHER_OPTIONS].flatten.each do |key|
if(options.has_key?(key)) if options.has_key?(key)
default_value = if(options[key].is_a?(Array)) default_value = if options[key].is_a?(Array)
options[key].join(",") options[key].join(",")
else else
options[key] options[key]
end end
end end
default_value = ENV[key.to_s] if(!ENV[key.to_s].blank?)
ENV[key.to_s] = default_value.to_s default_value = ENV[key.to_s] if !ENV[key.to_s].blank?
ENV[key.to_s] = default_value.nil? ? nil : default_value.to_s
end end
end end
...@@ -75,13 +79,34 @@ module Annotate ...@@ -75,13 +79,34 @@ module Annotate
options[:model_dir] = ['app/models'] options[:model_dir] = ['app/models']
end end
if(options[:root_dir].empty?)
options[:root_dir] = ['']
end
options[:wrapper_open] ||= options[:wrapper]
options[:wrapper_close] ||= options[:wrapper]
return options return options
end end
def self.reset_options
[POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS, OTHER_OPTIONS].flatten.each do |key|
ENV[key.to_s] = nil
end
end
def self.skip_on_migration? def self.skip_on_migration?
ENV['skip_on_db_migrate'] =~ TRUE_RE ENV['skip_on_db_migrate'] =~ TRUE_RE
end end
def self.include_routes?
ENV['routes'] =~ TRUE_RE
end
def self.include_models?
true
end
def self.loaded_tasks=(val); @loaded_tasks = val; end def self.loaded_tasks=(val); @loaded_tasks = val; end
def self.loaded_tasks; return @loaded_tasks; end def self.loaded_tasks; return @loaded_tasks; end
...@@ -124,7 +149,7 @@ module Annotate ...@@ -124,7 +149,7 @@ module Annotate
def self.bootstrap_rake def self.bootstrap_rake
begin begin
require 'rake/dsl_definition' require 'rake/dsl_definition'
rescue Exception => e rescue Exception
# We might just be on an old version of Rake... # We might just be on an old version of Rake...
end end
require 'rake' require 'rake'
......
...@@ -37,7 +37,8 @@ module AnnotateRoutes ...@@ -37,7 +37,8 @@ module AnnotateRoutes
"#" "#"
] + routes_map.map { |line| "# #{line}".rstrip } ] + routes_map.map { |line| "# #{line}".rstrip }
(content, where_header_found) = strip_annotations(File.read(routes_file)) existing_text = File.read(routes_file)
(content, where_header_found) = strip_annotations(existing_text)
changed = where_header_found != 0 # This will either be :before, :after, or changed = where_header_found != 0 # This will either be :before, :after, or
# a number. If the number is > 0, the # a number. If the number is > 0, the
# annotation was found somewhere in the # annotation was found somewhere in the
...@@ -60,21 +61,25 @@ module AnnotateRoutes ...@@ -60,21 +61,25 @@ module AnnotateRoutes
content = position_after ? (content + header) : header + content content = position_after ? (content + header) : header + content
write_contents(content) if write_contents(existing_text, content)
puts "#{routes_file} annotated."
puts "Route file annotated." else
puts "#{routes_file} unchanged."
end
end end
def self.remove_annotations(options={}) def self.remove_annotations(options={})
return unless(routes_exists?) return unless(routes_exists?)
existing_text = File.read(routes_file)
(content, where_header_found) = strip_annotations(File.read(routes_file)) (content, where_header_found) = strip_annotations(existing_text)
content = strip_on_removal(content, where_header_found) content = strip_on_removal(content, where_header_found)
write_contents(content) if write_contents(existing_text, content)
puts "Removed annotations from #{routes_file}."
puts "Removed annotations from routes file." else
puts "#{routes_file} unchanged."
end
end end
protected protected
...@@ -89,11 +94,15 @@ protected ...@@ -89,11 +94,15 @@ protected
return routes_exists return routes_exists
end end
def self.write_contents(content) def self.write_contents(existing_text, new_content)
content << '' unless(content.last == '') # Make sure we end on a trailing # Make sure we end on a trailing newline.
# newline. new_content << '' unless(new_content.last == '')
new_text = new_content.join("\n")
return false if existing_text == new_text
File.open(routes_file, "wb") { |f| f.puts(content.join("\n")) } File.open(routes_file, "wb") { |f| f.puts(new_text) }
return true
end end
def self.strip_annotations(content) def self.strip_annotations(content)
......
module Annotate module Annotate
def self.version def self.version
'2.6.10' '2.7.0'
end end
end end
...@@ -5,32 +5,42 @@ if Rails.env.development? ...@@ -5,32 +5,42 @@ if Rails.env.development?
task :set_annotation_options do task :set_annotation_options do
# You can override any of these by setting an environment variable of the # You can override any of these by setting an environment variable of the
# same name. # same name.
Annotate.set_defaults({ Annotate.set_defaults(
'position_in_routes' => "before", 'routes' => 'false',
'position_in_class' => "before", 'position_in_routes' => 'before',
'position_in_test' => "before", 'position_in_class' => 'before',
'position_in_fixture' => "before", 'position_in_test' => 'before',
'position_in_factory' => "before", 'position_in_fixture' => 'before',
'position_in_serializer' => "before", 'position_in_factory' => 'before',
'show_foreign_keys' => "true", 'position_in_serializer' => 'before',
'show_indexes' => "true", 'show_foreign_keys' => 'true',
'simple_indexes' => "false", 'show_indexes' => 'true',
'model_dir' => "app/models", 'simple_indexes' => 'false',
'include_version' => "false", 'model_dir' => 'app/models',
'require' => "", 'root_dir' => '',
'exclude_tests' => "false", 'include_version' => 'false',
'exclude_fixtures' => "false", 'require' => '',
'exclude_factories' => "false", 'exclude_tests' => 'false',
'exclude_serializers' => "false", 'exclude_fixtures' => 'false',
'ignore_model_sub_dir' => "false", 'exclude_factories' => 'false',
'skip_on_db_migrate' => "false", 'exclude_serializers' => 'false',
'format_bare' => "true", 'exclude_scaffolds' => 'false',
'format_rdoc' => "false", 'exclude_controllers' => 'false',
'format_markdown' => "false", 'exclude_helpers' => 'false',
'sort' => "false", 'ignore_model_sub_dir' => 'false',
'force' => "false", 'ignore_columns' => nil,
'trace' => "false", 'ignore_unknown_models' => 'false',
}) 'hide_limit_column_types' => '<%= AnnotateModels::NO_LIMIT_COL_TYPES.join(',') %>',
'skip_on_db_migrate' => 'false',
'format_bare' => 'true',
'format_rdoc' => 'false',
'format_markdown' => 'false',
'sort' => 'false',
'force' => 'false',
'trace' => 'false',
'wrapper_open' => nil,
'wrapper_close' => nil,
)
end end
Annotate.load_tasks Annotate.load_tasks
......
annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__))) annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__)))
if(!ENV['is_cli']) if !ENV['is_cli']
task :set_annotation_options task :set_annotation_options
task :annotate_models => :set_annotation_options task :annotate_models => :set_annotation_options
end end
...@@ -17,15 +17,20 @@ task :annotate_models => :environment do ...@@ -17,15 +17,20 @@ task :annotate_models => :environment do
options[:position_in_factory] = Annotate.fallback(ENV['position_in_factory'], ENV['position']) options[:position_in_factory] = Annotate.fallback(ENV['position_in_factory'], ENV['position'])
options[:position_in_test] = Annotate.fallback(ENV['position_in_test'], ENV['position']) options[:position_in_test] = Annotate.fallback(ENV['position_in_test'], ENV['position'])
options[:position_in_serializer] = Annotate.fallback(ENV['position_in_serializer'], ENV['position']) options[:position_in_serializer] = Annotate.fallback(ENV['position_in_serializer'], ENV['position'])
options[:show_foreign_keys] = Annotate.true?(ENV['show_foreign_keys'])
options[:show_indexes] = Annotate.true?(ENV['show_indexes']) options[:show_indexes] = Annotate.true?(ENV['show_indexes'])
options[:simple_indexes] = Annotate.true?(ENV['simple_indexes']) options[:simple_indexes] = Annotate.true?(ENV['simple_indexes'])
options[:model_dir] = ENV['model_dir'] ? ENV['model_dir'].split(',') : [] options[:model_dir] = ENV['model_dir'] ? ENV['model_dir'].split(',') : ['app/models']
options[:root_dir] = ENV['root_dir'] ? ENV['root_dir'].split(',') : ['']
options[:include_version] = Annotate.true?(ENV['include_version']) options[:include_version] = Annotate.true?(ENV['include_version'])
options[:require] = ENV['require'] ? ENV['require'].split(',') : [] options[:require] = ENV['require'] ? ENV['require'].split(',') : []
options[:exclude_tests] = Annotate.true?(ENV['exclude_tests']) options[:exclude_tests] = Annotate.true?(ENV['exclude_tests'])
options[:exclude_factories] = Annotate.true?(ENV['exclude_factories']) options[:exclude_factories] = Annotate.true?(ENV['exclude_factories'])
options[:exclude_fixtures] = Annotate.true?(ENV['exclude_fixtures']) options[:exclude_fixtures] = Annotate.true?(ENV['exclude_fixtures'])
options[:exclude_serializers] = Annotate.true?(ENV['exclude_serializers']) options[:exclude_serializers] = Annotate.true?(ENV['exclude_serializers'])
options[:exclude_scaffolds] = Annotate.true?(ENV['exclude_scaffolds'])
options[:exclude_controllers] = Annotate.true?(ENV['exclude_controllers'])
options[:exclude_helpers] = Annotate.true?(ENV['exclude_helpers'])
options[:ignore_model_sub_dir] = Annotate.true?(ENV['ignore_model_sub_dir']) options[:ignore_model_sub_dir] = Annotate.true?(ENV['ignore_model_sub_dir'])
options[:format_bare] = Annotate.true?(ENV['format_bare']) options[:format_bare] = Annotate.true?(ENV['format_bare'])
options[:format_rdoc] = Annotate.true?(ENV['format_rdoc']) options[:format_rdoc] = Annotate.true?(ENV['format_rdoc'])
...@@ -36,6 +41,8 @@ task :annotate_models => :environment do ...@@ -36,6 +41,8 @@ task :annotate_models => :environment do
options[:trace] = Annotate.true?(ENV['trace']) options[:trace] = Annotate.true?(ENV['trace'])
options[:wrapper_open] = Annotate.fallback(ENV['wrapper_open'], ENV['wrapper']) options[:wrapper_open] = Annotate.fallback(ENV['wrapper_open'], ENV['wrapper'])
options[:wrapper_close] = Annotate.fallback(ENV['wrapper_close'], ENV['wrapper']) options[:wrapper_close] = Annotate.fallback(ENV['wrapper_close'], ENV['wrapper'])
options[:ignore_columns] = ENV.fetch('ignore_columns', nil)
AnnotateModels.do_annotations(options) AnnotateModels.do_annotations(options)
end end
...@@ -46,6 +53,7 @@ task :remove_annotation => :environment do ...@@ -46,6 +53,7 @@ task :remove_annotation => :environment do
options={ :is_rake => true } options={ :is_rake => true }
options[:model_dir] = ENV['model_dir'] options[:model_dir] = ENV['model_dir']
options[:root_dir] = ENV['root_dir']
options[:require] = ENV['require'] ? ENV['require'].split(',') : [] options[:require] = ENV['require'] ? ENV['require'].split(',') : []
options[:trace] = Annotate.true?(ENV['trace']) options[:trace] = Annotate.true?(ENV['trace'])
AnnotateModels.remove_annotations(options) AnnotateModels.remove_annotations(options)
......
...@@ -2,20 +2,23 @@ ...@@ -2,20 +2,23 @@
# (They are not used to build annotate itself.) # (They are not used to build annotate itself.)
# Append annotations to Rake tasks for ActiveRecord, so annotate automatically gets # Append annotations to Rake tasks for ActiveRecord, so annotate automatically gets
# run after doing db:migrate. # run after doing db:migrate.
# Unfortunately it relies on ENV for options; it'd be nice to be able to set options
# in a per-project config file so this task can read them.
namespace :db do namespace :db do
task :migrate do [:migrate, :rollback].each do |cmd|
Annotate::Migration.update_annotations task cmd do
end Rake::Task['set_annotation_options'].invoke
Annotate::Migration.update_annotations
end
namespace :migrate do namespace cmd do
[:change, :up, :down, :reset, :redo].each do |t| [:change, :up, :down, :reset, :redo].each do |t|
task t do task t do
Annotate::Migration.update_annotations Rake::Task['set_annotation_options'].invoke
Annotate::Migration.update_annotations
end
end end
end end
end end
end end
...@@ -24,9 +27,25 @@ module Annotate ...@@ -24,9 +27,25 @@ module Annotate
@@working = false @@working = false
def self.update_annotations def self.update_annotations
unless @@working || (ENV['skip_on_db_migrate'] =~ /(true|t|yes|y|1)$/i) unless @@working || Annotate.skip_on_migration?
@@working = true @@working = true
Rake::Task['annotate_models'].invoke
self.update_models if Annotate.include_models?
self.update_routes if Annotate.include_routes?
end
end
def self.update_models
if Rake::Task.task_defined?("annotate_models")
Rake::Task["annotate_models"].invoke
elsif Rake::Task.task_defined?("app:annotate_models")
Rake::Task["app:annotate_models"].invoke
end
end
def self.update_routes
if Rake::Task.task_defined?("annotate_routes")
Rake::Task["annotate_routes"].invoke
end end
end end
end end
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
require File.dirname(__FILE__) + '/../spec_helper.rb' require File.dirname(__FILE__) + '/../spec_helper.rb'
require 'annotate/annotate_models' require 'annotate/annotate_models'
require 'annotate/active_record_patch' require 'annotate/active_record_patch'
require 'active_support/core_ext/string'
describe AnnotateModels do describe AnnotateModels do
def mock_foreign_key(name, from_column, to_table, to_column = 'id') def mock_foreign_key(name, from_column, to_table, to_column = 'id')
...@@ -17,6 +18,7 @@ describe AnnotateModels do ...@@ -17,6 +18,7 @@ describe AnnotateModels do
double("Conn", double("Conn",
:indexes => indexes, :indexes => indexes,
:foreign_keys => foreign_keys, :foreign_keys => foreign_keys,
:supports_foreign_keys? => true,
) )
end end
...@@ -56,11 +58,14 @@ describe AnnotateModels do ...@@ -56,11 +58,14 @@ describe AnnotateModels do
it { expect(AnnotateModels.quote(25)).to eql("25") } it { expect(AnnotateModels.quote(25)).to eql("25") }
it { expect(AnnotateModels.quote(25.6)).to eql("25.6") } it { expect(AnnotateModels.quote(25.6)).to eql("25.6") }
it { expect(AnnotateModels.quote(1e-20)).to eql("1.0e-20") } it { expect(AnnotateModels.quote(1e-20)).to eql("1.0e-20") }
it { expect(AnnotateModels.quote(BigDecimal.new("1.2"))).to eql("1.2") }
it { expect(AnnotateModels.quote([BigDecimal.new("1.2")])).to eql(["1.2"]) }
it "should get schema info" do it "should get schema info with default options" do
klass = mock_class(:users, :id, [ klass = mock_class(:users, :id, [
mock_column(:id, :integer), mock_column(:id, :integer, :limit => 8),
mock_column(:name, :string, :limit => 50) mock_column(:name, :string, :limit => 50),
mock_column(:notes, :text, :limit => 55),
]) ])
expect(AnnotateModels.get_schema_info(klass, "Schema Info")).to eql(<<-EOS) expect(AnnotateModels.get_schema_info(klass, "Schema Info")).to eql(<<-EOS)
...@@ -68,8 +73,9 @@ describe AnnotateModels do ...@@ -68,8 +73,9 @@ describe AnnotateModels do
# #
# Table name: users # Table name: users
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(50) not null # name :string(50) not null
# notes :text(55) not null
# #
EOS EOS
end end
...@@ -189,6 +195,61 @@ EOS ...@@ -189,6 +195,61 @@ EOS
EOS EOS
end end
describe "#get_schema_info with custom options" do
def self.when_called_with(options = {})
expected = options.delete(:returns)
it "should work with options = #{options}" do
klass = mock_class(:users, :id, [
mock_column(:id, :integer, :limit => 8),
mock_column(:active, :boolean, :limit => 1),
mock_column(:name, :string, :limit => 50),
mock_column(:notes, :text, :limit => 55),
])
schema_info = AnnotateModels.get_schema_info(klass, "Schema Info", options)
expect(schema_info).to eql(expected)
end
end
when_called_with hide_limit_column_types: '', returns: <<-EOS.strip_heredoc
# Schema Info
#
# Table name: users
#
# id :integer not null, primary key
# active :boolean not null
# name :string(50) not null
# notes :text(55) not null
#
EOS
when_called_with hide_limit_column_types: 'integer,boolean', returns:
<<-EOS.strip_heredoc
# Schema Info
#
# Table name: users
#
# id :integer not null, primary key
# active :boolean not null
# name :string(50) not null
# notes :text(55) not null
#
EOS
when_called_with hide_limit_column_types: 'integer,boolean,string,text', returns:
<<-EOS.strip_heredoc
# Schema Info
#
# Table name: users
#
# id :integer not null, primary key
# active :boolean not null
# name :string not null
# notes :text not null
#
EOS
end
describe "#get_model_class" do describe "#get_model_class" do
require "tmpdir" require "tmpdir"
...@@ -435,6 +496,35 @@ end ...@@ -435,6 +496,35 @@ end
end end
end end
describe '#resolve_filename' do
it 'should return the test path for a model' do
filename_template = 'test/unit/%MODEL_NAME%_test.rb'
model_name = 'example_model'
table_name = 'example_models'
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq 'test/unit/example_model_test.rb'
end
it 'should return the fixture path for a model' do
filename_template = 'test/fixtures/%TABLE_NAME%.yml'
model_name = 'example_model'
table_name = 'example_models'
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq 'test/fixtures/example_models.yml'
end
it 'should return the fixture path for a nested model' do
filename_template = 'test/fixtures/%PLURALIZED_MODEL_NAME%.yml'
model_name = 'parent/child'
table_name = 'parent_children'
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq 'test/fixtures/parent/children.yml'
end
end
describe "annotating a file" do describe "annotating a file" do
before do before do
@model_dir = Dir.mktmpdir('annotate_models') @model_dir = Dir.mktmpdir('annotate_models')
...@@ -448,6 +538,7 @@ end ...@@ -448,6 +538,7 @@ end
mock_column(:name, :string, :limit => 50) mock_column(:name, :string, :limit => 50)
]) ])
@schema_info = AnnotateModels.get_schema_info(@klass, "== Schema Info") @schema_info = AnnotateModels.get_schema_info(@klass, "== Schema Info")
Annotate.reset_options
end end
def write_model file_name, file_content def write_model file_name, file_content
...@@ -469,14 +560,20 @@ end ...@@ -469,14 +560,20 @@ end
Annotate::PATH_OPTIONS.each { |key| ENV[key.to_s] = '' } Annotate::PATH_OPTIONS.each { |key| ENV[key.to_s] = '' }
end end
def encoding_comments_list_each def magic_comments_list_each
[ [
'# encoding: UTF-8', '# encoding: UTF-8',
'# coding: UTF-8', '# coding: UTF-8',
'# -*- coding: UTF-8 -*-', '# -*- coding: UTF-8 -*-',
'#encoding: utf-8', '#encoding: utf-8',
'# -*- encoding : utf-8 -*-' '# encoding: utf-8',
].each{|encoding_comment| yield encoding_comment } '# -*- encoding : utf-8 -*-',
"# encoding: utf-8\n# frozen_string_literal: true",
"# frozen_string_literal: true\n# encoding: utf-8",
'# frozen_string_literal: true',
'#frozen_string_literal: false',
'# -*- frozen_string_literal : true -*-',
].each{|magic_comment| yield magic_comment }
end end
it "should put annotation before class if :position == 'before'" do it "should put annotation before class if :position == 'before'" do
...@@ -521,7 +618,7 @@ end ...@@ -521,7 +618,7 @@ end
it 'should wrap annotation if wrapper is specified' do it 'should wrap annotation if wrapper is specified' do
annotate_one_file :wrapper_open => 'START', :wrapper_close => 'END' annotate_one_file :wrapper_open => 'START', :wrapper_close => 'END'
expect(File.read(@model_file_name)).to eq("# START\n#{@schema_info}\n# END\n#{@file_content}") expect(File.read(@model_file_name)).to eq("# START\n#{@schema_info}# END\n\n#{@file_content}")
end end
describe "with existing annotation => :before" do describe "with existing annotation => :before" do
...@@ -593,17 +690,22 @@ end ...@@ -593,17 +690,22 @@ end
expect(File.read(model_file_name)).to eq("#{schema_info}\n#{file_content}") expect(File.read(model_file_name)).to eq("#{schema_info}\n#{file_content}")
end end
it "should not touch encoding comments" do it "should not touch magic comments" do
encoding_comments_list_each do |encoding_comment| magic_comments_list_each do |magic_comment|
write_model "user.rb", <<-EOS write_model "user.rb", <<-EOS
#{encoding_comment} #{magic_comment}
class User < ActiveRecord::Base class User < ActiveRecord::Base
end end
EOS EOS
annotate_one_file :position => :before annotate_one_file :position => :before
expect(File.open(@model_file_name, &:readline)).to eq("#{encoding_comment}\n") lines= magic_comment.split("\n")
File.open @model_file_name do |file|
lines.count.times do |index|
expect(file.readline).to eq "#{lines[index]}\n"
end
end
end end
end end
......
...@@ -2,85 +2,114 @@ require File.dirname(__FILE__) + '/../spec_helper.rb' ...@@ -2,85 +2,114 @@ require File.dirname(__FILE__) + '/../spec_helper.rb'
require 'annotate/annotate_routes' require 'annotate/annotate_routes'
describe AnnotateRoutes do describe AnnotateRoutes do
ROUTE_FILE = "config/routes.rb"
ANNOTATION_ADDED = "#{ROUTE_FILE} annotated."
ANNOTATION_REMOVED = "Removed annotations from #{ROUTE_FILE}."
FILE_UNCHANGED = "#{ROUTE_FILE} unchanged."
def mock_file(stubs={}) def mock_file(stubs={})
@mock_file ||= double(File, stubs) @mock_file ||= double(File, stubs)
end end
it "should check if routes.rb exists" do it "should check if routes.rb exists" do
expect(File).to receive(:exists?).with("config/routes.rb").and_return(false) expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(false)
expect(AnnotateRoutes).to receive(:puts).with("Can`t find routes.rb") expect(AnnotateRoutes).to receive(:puts).with("Can`t find routes.rb")
AnnotateRoutes.do_annotations AnnotateRoutes.do_annotations
end end
describe "When Annotating, with older Rake Versions" do describe "When adding" do
before(:each) do
expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(true)
expect(AnnotateRoutes).to receive(:`).with("rake routes").and_return("")
end
it "should insert annotations if file does not contain annotations" do
expect(File).to receive(:read).with(ROUTE_FILE).and_return("")
expect(File).to receive(:open).with(ROUTE_FILE, "wb").and_yield(mock_file)
expect(@mock_file).to receive(:puts).with("\n# == Route Map\n#\n")
expect(AnnotateRoutes).to receive(:puts).with(ANNOTATION_ADDED)
AnnotateRoutes.do_annotations
end
it "should skip annotations if file does already contain annotation" do
expect(File).to receive(:read).with(ROUTE_FILE).and_return("\n# == Route Map\n#\n")
expect(AnnotateRoutes).to receive(:puts).with(FILE_UNCHANGED)
AnnotateRoutes.do_annotations
end
end
describe "When adding with older Rake versions" do
before(:each) do before(:each) do
expect(File).to receive(:exists?).with("config/routes.rb").and_return(true) expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(true)
expect(AnnotateRoutes).to receive(:`).with("rake routes").and_return("(in /bad/line)\ngood line") expect(AnnotateRoutes).to receive(:`).with("rake routes").and_return("(in /bad/line)\ngood line")
expect(File).to receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) expect(File).to receive(:open).with(ROUTE_FILE, "wb").and_yield(mock_file)
expect(AnnotateRoutes).to receive(:puts).with("Route file annotated.") expect(AnnotateRoutes).to receive(:puts).with(ANNOTATION_ADDED)
end end
it "should annotate and add a newline!" do it "should annotate and add a newline!" do
expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo") expect(File).to receive(:read).with(ROUTE_FILE).and_return("ActionController::Routing...\nfoo")
expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map\n#\n# good line\n/) expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map\n#\n# good line\n/)
AnnotateRoutes.do_annotations AnnotateRoutes.do_annotations
end end
it "should not add a newline if there are empty lines" do it "should not add a newline if there are empty lines" do
expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n") expect(File).to receive(:read).with(ROUTE_FILE).and_return("ActionController::Routing...\nfoo\n")
expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map\n#\n# good line\n/) expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map\n#\n# good line\n/)
AnnotateRoutes.do_annotations AnnotateRoutes.do_annotations
end end
end end
describe "When Annotating, with newer Rake Versions" do describe "When adding with newer Rake versions" do
before(:each) do before(:each) do
expect(File).to receive(:exists?).with("config/routes.rb").and_return(true) expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(true)
expect(AnnotateRoutes).to receive(:`).with("rake routes").and_return("another good line\ngood line") expect(AnnotateRoutes).to receive(:`).with("rake routes").and_return("another good line\ngood line")
expect(File).to receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) expect(File).to receive(:open).with(ROUTE_FILE, "wb").and_yield(mock_file)
expect(AnnotateRoutes).to receive(:puts).with("Route file annotated.") expect(AnnotateRoutes).to receive(:puts).with(ANNOTATION_ADDED)
end end
it "should annotate and add a newline!" do it "should annotate and add a newline!" do
expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo") expect(File).to receive(:read).with(ROUTE_FILE).and_return("ActionController::Routing...\nfoo")
expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map\n#\n# another good line\n# good line\n/) expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map\n#\n# another good line\n# good line\n/)
AnnotateRoutes.do_annotations AnnotateRoutes.do_annotations
end end
it "should not add a newline if there are empty lines" do it "should not add a newline if there are empty lines" do
expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n") expect(File).to receive(:read).with(ROUTE_FILE).and_return("ActionController::Routing...\nfoo\n")
expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map\n#\n# another good line\n# good line\n/) expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map\n#\n# another good line\n# good line\n/)
AnnotateRoutes.do_annotations AnnotateRoutes.do_annotations
end end
it "should add a timestamp when :timestamp is passed" do it "should add a timestamp when :timestamp is passed" do
expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo") expect(File).to receive(:read).with(ROUTE_FILE).and_return("ActionController::Routing...\nfoo")
expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# another good line\n# good line\n/) expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# another good line\n# good line\n/)
AnnotateRoutes.do_annotations :timestamp => true AnnotateRoutes.do_annotations :timestamp => true
end end
end end
describe "When Removing Annotation" do describe "When removing" do
before(:each) do before(:each) do
expect(File).to receive(:exists?).with("config/routes.rb").and_return(true) expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(true)
expect(File).to receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) expect(File).to receive(:open).with(ROUTE_FILE, "wb").and_yield(mock_file)
expect(AnnotateRoutes).to receive(:puts).with("Removed annotations from routes file.") expect(AnnotateRoutes).to receive(:puts).with(ANNOTATION_REMOVED)
end end
it "should remove trailing annotation and trim trailing newlines, but leave leading newlines alone" do it "should remove trailing annotation and trim trailing newlines, but leave leading newlines alone" do
expect(File).to receive(:read).with("config/routes.rb").and_return("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n# == Route Map\n#\n# another good line\n# good line\n") expect(File).to receive(:read).with(ROUTE_FILE).and_return("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n# == Route Map\n#\n# another good line\n# good line\n")
expect(@mock_file).to receive(:puts).with(/\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n/) expect(@mock_file).to receive(:puts).with(/\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n/)
AnnotateRoutes.remove_annotations AnnotateRoutes.remove_annotations
end end
it "should remove prepended annotation and trim leading newlines, but leave trailing newlines alone" do it "should remove prepended annotation and trim leading newlines, but leave trailing newlines alone" do
expect(File).to receive(:read).with("config/routes.rb").and_return("# == Route Map\n#\n# another good line\n# good line\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n") expect(File).to receive(:read).with(ROUTE_FILE).and_return("# == Route Map\n#\n# another good line\n# good line\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n")
expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n/) expect(@mock_file).to receive(:puts).with(/ActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n/)
AnnotateRoutes.remove_annotations AnnotateRoutes.remove_annotations
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment