Commit d1ca3549 by cuong.tran

Merge branch 'release/2.6.4'

parents c60fa282 b5bf438e
== 2.6.4
* Skip "models/concerns", #194
* Fix #173 where annotate says "Nothing to annotate" in rails 4.2
* Display an error message if not run from the root of the project, #186
* Support rails 4.0 new default test directory, #182
* Add an option to show timestamp in routes "-timestamp", #136
* Skip plain ruby objects if they have the same class name as an ActiveRecord object, #121
== 2.6.3 == 2.6.3
* Fix bug of annotate position in routes (#158) * Fix bug of annotate position in routes (#158)
......
...@@ -13,6 +13,8 @@ end ...@@ -13,6 +13,8 @@ end
group :development, :test do group :development, :test do
gem 'rspec', :require => false gem 'rspec', :require => false
gem 'guard-rspec', require: false
platforms :mri do platforms :mri do
gem 'pry', :require => false gem 'pry', :require => false
gem 'pry-coolline', :require => false gem 'pry-coolline', :require => false
......
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard :rspec do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }
# Capybara features specs
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end
guard :rspec do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }
# Capybara features specs
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end
...@@ -54,7 +54,7 @@ Into Gemfile from rubygems.org: ...@@ -54,7 +54,7 @@ Into Gemfile from rubygems.org:
Into Gemfile from Github: Into Gemfile from Github:
gem 'annotate', :git => 'git://github.com/ctran/annotate_models.git' gem 'annotate', github: 'ctran/annotate_models'
Into environment gems from rubygems.org: Into environment gems from rubygems.org:
...@@ -179,6 +179,7 @@ you can do so with a simple environment variable, instead of editing the ...@@ -179,6 +179,7 @@ you can do so with a simple environment variable, instead of editing the
--format --format
--force Force new annotations even if there are no changes. --force Force new annotations even if there are no changes.
--trace If unable to annotate a file, print the full stack trace, not just the exception message. --trace If unable to annotate a file, print the full stack trace, not just the exception message.
--timestamp Include an updated time in routes.rb
== Sorting == Sorting
......
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
# stub: annotate 2.6.3 ruby lib lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'annotate/version'
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "annotate" s.name = "annotate"
s.version = "2.6.3" s.version = Annotate.version
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Cuong Tran", "Alex Chaffee", "Marcos Piccinini", "Turadg Aleahmad", "Jon Frisby"] s.authors = ["Cuong Tran", "Alex Chaffee", "Marcos Piccinini", "Turadg Aleahmad", "Jon Frisby"]
......
#!/usr/bin/env ruby #!/usr/bin/env ruby
unless File.exists?('./Rakefile') || File.exists?('./Gemfile')
abort "Please run annotate from the root of the project."
end
require 'rubygems' require 'rubygems'
begin begin
require 'bundler' require 'bundler'
...@@ -132,6 +137,10 @@ OptionParser.new do |opts| ...@@ -132,6 +137,10 @@ OptionParser.new do |opts|
ENV['force'] = 'yes' ENV['force'] = 'yes'
end end
opts.on('--timestamp', 'Include timestamp in (routes) annotation') do
ENV['timestamp'] = 'true'
end
opts.on('--trace', 'If unable to annotate a file, print the full stack trace, not just the exception message.') do |value| opts.on('--trace', 'If unable to annotate a file, print the full stack trace, not just the exception message.') do |value|
ENV['trace'] = 'yes' ENV['trace'] = 'yes'
end end
...@@ -142,7 +151,6 @@ OptionParser.new do |opts| ...@@ -142,7 +151,6 @@ OptionParser.new do |opts|
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'].blank? })
Annotate.eager_load(options) Annotate.eager_load(options)
target[:klass].send(target[:task], options) target[:klass].send(target[:task], options)
...@@ -22,7 +22,7 @@ module Annotate ...@@ -22,7 +22,7 @@ module Annotate
FLAG_OPTIONS=[ FLAG_OPTIONS=[
:show_indexes, :simple_indexes, :include_version, :exclude_tests, :show_indexes, :simple_indexes, :include_version, :exclude_tests,
: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
] ]
OTHER_OPTIONS=[ OTHER_OPTIONS=[
:model_dir, :ignore_columns :model_dir, :ignore_columns
......
...@@ -10,6 +10,7 @@ module AnnotateModels ...@@ -10,6 +10,7 @@ module AnnotateModels
# File.join for windows reverse bar compat? # File.join for windows reverse bar compat?
# I dont use windows, can`t test # I dont use windows, can`t test
UNIT_TEST_DIR = File.join("test", "unit") UNIT_TEST_DIR = File.join("test", "unit")
MODEL_TEST_DIR = File.join("test", "models") # since rails 4.0
SPEC_MODEL_DIR = File.join("spec", "models") SPEC_MODEL_DIR = File.join("spec", "models")
FIXTURE_TEST_DIR = File.join("test", "fixtures") FIXTURE_TEST_DIR = File.join("test", "fixtures")
FIXTURE_SPEC_DIR = File.join("spec", "fixtures") FIXTURE_SPEC_DIR = File.join("spec", "fixtures")
...@@ -32,6 +33,7 @@ module AnnotateModels ...@@ -32,6 +33,7 @@ module AnnotateModels
TEST_PATTERNS = [ TEST_PATTERNS = [
File.join(UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"), File.join(UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"),
File.join(MODEL_TEST_DIR, "%MODEL_NAME%_test.rb"),
File.join(SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb"), File.join(SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb"),
] ]
...@@ -121,7 +123,7 @@ module AnnotateModels ...@@ -121,7 +123,7 @@ module AnnotateModels
col_type = (col.type || col.sql_type).to_s col_type = (col.type || col.sql_type).to_s
if col_type == "decimal" if col_type == "decimal"
col_type << "(#{col.precision}, #{col.scale})" col_type << "(#{col.precision}, #{col.scale})"
elsif col_type != "spatial" elsif col_type != "spatial"
if (col.limit) if (col.limit)
if col.limit.is_a? Array if col.limit.is_a? Array
attrs << "(#{col.limit.join(', ')})" attrs << "(#{col.limit.join(', ')})"
...@@ -140,7 +142,7 @@ module AnnotateModels ...@@ -140,7 +142,7 @@ module AnnotateModels
# and print the type and SRID # and print the type and SRID
if col.respond_to?(:geometry_type) if col.respond_to?(:geometry_type)
attrs << "#{col.geometry_type}, #{col.srid}" attrs << "#{col.geometry_type}, #{col.srid}"
elsif col.respond_to?(:geometric_type) and col.geometric_type.present? elsif col.respond_to?(:geometric_type) and col.geometric_type.present?
attrs << "#{col.geometric_type.to_s.downcase}, #{col.srid}" attrs << "#{col.geometric_type.to_s.downcase}, #{col.srid}"
end end
...@@ -222,7 +224,7 @@ module AnnotateModels ...@@ -222,7 +224,7 @@ module AnnotateModels
old_header = old_content.match(header_pattern).to_s old_header = old_content.match(header_pattern).to_s
new_header = info_block.match(header_pattern).to_s new_header = info_block.match(header_pattern).to_s
column_pattern = /^#[\t ]+\w+[\t ]+.+$/ column_pattern = /^#[\t ]+[\w\*`]+[\t ]+.+$/
old_columns = old_header && old_header.scan(column_pattern).sort old_columns = old_header && old_header.scan(column_pattern).sort
new_columns = new_header && new_header.scan(column_pattern).sort new_columns = new_header && new_header.scan(column_pattern).sort
...@@ -235,10 +237,10 @@ module AnnotateModels ...@@ -235,10 +237,10 @@ module AnnotateModels
# Replace inline the old schema info with the new schema info # Replace inline the old schema info with the new schema info
new_content = old_content.sub(PATTERN, info_block + "\n") new_content = old_content.sub(PATTERN, info_block + "\n")
if new_content.end_with? (info_block + "\n") if new_content.end_with?(info_block + "\n")
new_content = old_content.sub(PATTERN, "\n" + info_block) new_content = old_content.sub(PATTERN, "\n" + info_block)
end end
# if there *was* no old schema info (no substitution happened) or :force was passed, # if there *was* no old schema info (no substitution happened) or :force was passed,
# we simply need to insert it in correct position # we simply need to insert it in correct position
if new_content == old_content || options[:force] if new_content == old_content || options[:force]
...@@ -352,7 +354,7 @@ module AnnotateModels ...@@ -352,7 +354,7 @@ module AnnotateModels
models = if options[:ignore_model_sub_dir] models = if options[:ignore_model_sub_dir]
Dir["*.rb"] Dir["*.rb"]
else else
Dir["**/*.rb"] Dir["**/*.rb"].reject{ |f| f["concerns/"] }
end end
end end
rescue SystemCallError rescue SystemCallError
...@@ -369,21 +371,36 @@ module AnnotateModels ...@@ -369,21 +371,36 @@ module AnnotateModels
# Check for namespaced models in subdirectories as well as models # Check for namespaced models in subdirectories as well as models
# in subdirectories without namespacing. # in subdirectories without namespacing.
def get_model_class(file) def get_model_class(file)
# this is for non-rails projects, which don't get Rails auto-require magic
require File.expand_path("#{model_dir}/#{file}")
model_path = file.gsub(/\.rb$/, '') model_path = file.gsub(/\.rb$/, '')
get_loaded_model(model_path) || get_loaded_model(model_path.split('/').last) begin
get_loaded_model(model_path) or raise LoadError.new("cannot load a model from #{file}")
rescue LoadError
# this is for non-rails projects, which don't get Rails auto-require magic
if Kernel.require(File.expand_path("#{model_dir}/#{model_path}"))
retry
elsif model_path.match(/\//)
model_path = model_path.split('/')[1..-1].join('/').to_s
retry
else
raise
end
end
end end
# Retrieve loaded model class by path to the file where it's supposed to be defined. # Retrieve loaded model class by path to the file where it's supposed to be defined.
def get_loaded_model(model_path) def get_loaded_model(model_path)
ObjectSpace.each_object(::Class). begin
select do |c| ActiveSupport::Inflector.constantize(ActiveSupport::Inflector.camelize(model_path))
Class === c and # note: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a? rescue
c.ancestors.respond_to?(:include?) and # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82 # Revert to the old way but it is not really robust
c.ancestors.include?(ActiveRecord::Base) ObjectSpace.each_object(::Class).
end. select do |c|
detect { |c| ActiveSupport::Inflector.underscore(c) == model_path } Class === c and # note: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a?
c.ancestors.respond_to?(:include?) and # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82
c.ancestors.include?(ActiveRecord::Base)
end.
detect { |c| ActiveSupport::Inflector.underscore(c.to_s) == model_path }
end
end end
# We're passed a name of things that might be # We're passed a name of things that might be
...@@ -428,7 +445,6 @@ module AnnotateModels ...@@ -428,7 +445,6 @@ module AnnotateModels
end end
def remove_annotations(options={}) def remove_annotations(options={})
self.model_dir = options[:model_dir] if options[:model_dir] self.model_dir = options[:model_dir] if options[:model_dir]
deannotated = [] deannotated = []
deannotated_klass = false deannotated_klass = false
......
...@@ -33,7 +33,7 @@ module AnnotateRoutes ...@@ -33,7 +33,7 @@ module AnnotateRoutes
routes_map.shift if(routes_map.first =~ /^\(in \//) routes_map.shift if(routes_map.first =~ /^\(in \//)
header = [ header = [
"#{PREFIX} (Updated #{Time.now.strftime("%Y-%m-%d %H:%M")})", "#{PREFIX}" + (options[:timestamp] ? " (Updated #{Time.now.strftime("%Y-%m-%d %H:%M")})" : ""),
"#" "#"
] + routes_map.map { |line| "# #{line}".rstrip } ] + routes_map.map { |line| "# #{line}".rstrip }
......
module Annotate module Annotate
def self.version def self.version
'2.6.3' '2.6.4'
end end
end end
# NOTE: only doing this in development as some production environments (Heroku) # NOTE: only doing this in development as some production environments (Heroku)
# NOTE: are sensitive to local FS writes, and besides -- it's just not proper # NOTE: are sensitive to local FS writes, and besides -- it's just not proper
# NOTE: to have a dev-mode tool do its thing in production. # NOTE: to have a dev-mode tool do its thing in production.
if(Rails.env.development?) 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.
......
...@@ -8,29 +8,29 @@ describe AnnotateRoutes do ...@@ -8,29 +8,29 @@ describe AnnotateRoutes do
end end
it "should check if routes.rb exists" do it "should check if routes.rb exists" do
File.should_receive(:exists?).with("config/routes.rb").and_return(false) expect(File).to receive(:exists?).with("config/routes.rb").and_return(false)
AnnotateRoutes.should_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 Annotating, with older Rake Versions" do
before(:each) do before(:each) do
File.should_receive(:exists?).with("config/routes.rb").and_return(true) expect(File).to receive(:exists?).with("config/routes.rb").and_return(true)
AnnotateRoutes.should_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")
File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) expect(File).to receive(:open).with("config/routes.rb", "wb").and_yield(mock_file)
AnnotateRoutes.should_receive(:puts).with("Route file annotated.") expect(AnnotateRoutes).to receive(:puts).with("Route file annotated.")
end end
it "should annotate and add a newline!" do it "should annotate and add a newline!" do
File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo") expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo")
@mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\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
File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n") expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n")
@mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\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
...@@ -39,43 +39,49 @@ describe AnnotateRoutes do ...@@ -39,43 +39,49 @@ describe AnnotateRoutes do
describe "When Annotating, with newer Rake Versions" do describe "When Annotating, with newer Rake Versions" do
before(:each) do before(:each) do
File.should_receive(:exists?).with("config/routes.rb").and_return(true) expect(File).to receive(:exists?).with("config/routes.rb").and_return(true)
AnnotateRoutes.should_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")
File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) expect(File).to receive(:open).with("config/routes.rb", "wb").and_yield(mock_file)
AnnotateRoutes.should_receive(:puts).with("Route file annotated.") expect(AnnotateRoutes).to receive(:puts).with("Route file annotated.")
end end
it "should annotate and add a newline!" do it "should annotate and add a newline!" do
File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo") expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo")
@mock_file.should_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\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
File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n") expect(File).to receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n")
@mock_file.should_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\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
expect(File).to receive(:read).with("config/routes.rb").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/)
AnnotateRoutes.do_annotations :timestamp => true
end
end end
describe "When Removing Annotation" do describe "When Removing Annotation" do
before(:each) do before(:each) do
File.should_receive(:exists?).with("config/routes.rb").and_return(true) expect(File).to receive(:exists?).with("config/routes.rb").and_return(true)
File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) expect(File).to receive(:open).with("config/routes.rb", "wb").and_yield(mock_file)
AnnotateRoutes.should_receive(:puts).with("Removed annotations from routes file.") expect(AnnotateRoutes).to receive(:puts).with("Removed annotations from routes file.")
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
File.should_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 (Updated 2012-08-16 00:00)\n#\n# another good line\n# good line\n") 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")
@mock_file.should_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
File.should_receive(:read).with("config/routes.rb").and_return("# == Route Map (Updated 2012-08-16 00:00)\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("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")
@mock_file.should_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
......
...@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/spec_helper.rb' ...@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/spec_helper.rb'
describe Annotate do describe Annotate do
it "should have a version" do it "should have a version" do
Annotate.version.should be_instance_of(String) expect(Annotate.version).to be_instance_of(String)
end end
end end
...@@ -38,6 +38,11 @@ module Annotate ...@@ -38,6 +38,11 @@ module Annotate
File.read("test/unit/task_test.rb").should == unittest File.read("test/unit/task_test.rb").should == unittest
end end
def self.check_task_modeltest(test_rig, annotation, place_before=true)
unittest = apply_annotation(test_rig, "test/models/task_test.rb", annotation, place_before)
File.read("test/models/task_test.rb").should == unittest
end
def self.check_task_factory(test_rig, annotation, place_before=true) def self.check_task_factory(test_rig, annotation, place_before=true)
fixture = apply_annotation(test_rig, "test/factories/tasks.rb", annotation, place_before) fixture = apply_annotation(test_rig, "test/factories/tasks.rb", annotation, place_before)
File.read("test/factories/tasks.rb").should == fixture File.read("test/factories/tasks.rb").should == fixture
......
...@@ -27,19 +27,19 @@ describe "annotate inside Rails, using #{CURRENT_RUBY}" do ...@@ -27,19 +27,19 @@ describe "annotate inside Rails, using #{CURRENT_RUBY}" do
next if(chosen_scenario && chosen_scenario != test_rig) next if(chosen_scenario && chosen_scenario != test_rig)
it "works under #{test_name}" do it "works under #{test_name}" do
if(!USING_RVM) if(!USING_RVM)
pending "Must have RVM installed." skip "Must have RVM installed."
next next
end end
# Don't proceed if the working copy is dirty! # Don't proceed if the working copy is dirty!
Annotate::Integration.is_clean?(test_rig).should == true expect(Annotate::Integration.is_clean?(test_rig)).to eq(true)
pending "temporarily ignored until Travis can run them" skip "temporarily ignored until Travis can run them"
Bundler.with_clean_env do Bundler.with_clean_env do
dir base_dir do dir base_dir do
temp_dir = Dir.pwd temp_dir = Dir.pwd
File.basename(temp_dir).should == base_dir expect(File.basename(temp_dir)).to eq(base_dir)
# Delete cruft from hands-on debugging... # Delete cruft from hands-on debugging...
Annotate::Integration.nuke_cruft(test_rig) Annotate::Integration.nuke_cruft(test_rig)
......
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config.
/.bundle
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*.log
/tmp
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.1.1'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.3'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring', group: :development
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use unicorn as the app server
# gem 'unicorn'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
# Use debugger
# gem 'debugger', group: [:development, :test]
group :development do
if(ENV['AUTOMATED_TEST'] && ENV['AUTOMATED_TEST'] != '')
gem 'annotate', :path => ENV['AUTOMATED_TEST']
else
gem 'annotate', :path => '../../..'
end
end
gem 'rails-observers'
PATH
remote: ../../..
specs:
annotate (2.6.3)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.1.1)
actionpack (= 4.1.1)
actionview (= 4.1.1)
mail (~> 2.5.4)
actionpack (4.1.1)
actionview (= 4.1.1)
activesupport (= 4.1.1)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
actionview (4.1.1)
activesupport (= 4.1.1)
builder (~> 3.1)
erubis (~> 2.7.0)
activemodel (4.1.1)
activesupport (= 4.1.1)
builder (~> 3.1)
activerecord (4.1.1)
activemodel (= 4.1.1)
activesupport (= 4.1.1)
arel (~> 5.0.0)
activesupport (4.1.1)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
arel (5.0.1.20140414130214)
builder (3.2.2)
coffee-rails (4.0.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.0)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.7.0)
erubis (2.7.0)
execjs (2.0.2)
hike (1.2.3)
i18n (0.6.9)
jbuilder (2.0.7)
activesupport (>= 3.0.0, < 5)
multi_json (~> 1.2)
jquery-rails (3.1.0)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.25.1)
minitest (5.3.4)
multi_json (1.10.1)
polyglot (0.3.4)
rack (1.5.2)
rack-test (0.6.2)
rack (>= 1.0)
rails (4.1.1)
actionmailer (= 4.1.1)
actionpack (= 4.1.1)
actionview (= 4.1.1)
activemodel (= 4.1.1)
activerecord (= 4.1.1)
activesupport (= 4.1.1)
bundler (>= 1.3.0, < 2.0)
railties (= 4.1.1)
sprockets-rails (~> 2.0)
rails-observers (0.1.2)
activemodel (~> 4.0)
railties (4.1.1)
actionpack (= 4.1.1)
activesupport (= 4.1.1)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.3.2)
rdoc (4.1.1)
json (~> 1.4)
sass (3.2.19)
sass-rails (4.0.3)
railties (>= 4.0.0, < 5.0)
sass (~> 3.2.0)
sprockets (~> 2.8, <= 2.11.0)
sprockets-rails (~> 2.0)
sdoc (0.4.0)
json (~> 1.8)
rdoc (~> 4.0, < 5.0)
spring (1.1.3)
sprockets (2.11.0)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.1.3)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.8)
sqlite3 (1.3.9)
thor (0.19.1)
thread_safe (0.3.3)
tilt (1.4.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
turbolinks (2.2.2)
coffee-rails
tzinfo (1.1.0)
thread_safe (~> 0.1)
uglifier (2.5.0)
execjs (>= 0.3.0)
json (>= 1.8.0)
PLATFORMS
ruby
DEPENDENCIES
annotate!
coffee-rails (~> 4.0.0)
jbuilder (~> 2.0)
jquery-rails
rails (= 4.1.1)
rails-observers
sass-rails (~> 4.0.3)
sdoc (~> 0.4.0)
spring
sqlite3
turbolinks
uglifier (>= 1.3.0)
== README
This README would normally document whatever steps are necessary to get the
application up and running.
Things you may want to cover:
* Ruby version
* System dependencies
* Configuration
* Database creation
* Database initialization
* How to run the test suite
* Services (job queues, cache servers, search engines, etc.)
* Deployment instructions
* ...
Please feel free to use a different markup language if you do not plan to run
<tt>rake doc:app</tt>.
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks
class Task < ActiveRecord::Base
enum status: %w(normal active completed)
end
class TaskObserver < ActiveRecord::Observer
end
\ No newline at end of file
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run Rails.application
require File.expand_path('../boot', __FILE__)
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Rails411
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
end
end
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
# SQLite version 3.x
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem 'sqlite3'
#
default: &default
adapter: sqlite3
pool: 5
timeout: 5000
development:
<<: *default
database: db/development.sqlite3
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: db/test.sqlite3
production:
<<: *default
database: db/production.sqlite3
# Load the Rails application.
require File.expand_path('../application', __FILE__)
# Initialize the Rails application.
Rails.application.initialize!
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
# config.action_dispatch.rack_cache = true
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Generate digests for assets URLs.
config.assets.digest = true
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Set to :debug to see everything in the log.
config.log_level = :info
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
# Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = "http://assets.example.com"
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# config.assets.precompile += %w( search.js )
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Disable automatic flushing of the log to improve performance.
# config.autoflush_log = false
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
end
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure static asset server for tests with Cache-Control for performance.
config.serve_static_assets = true
config.static_cache_control = 'public, max-age=3600'
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
# Be sure to restart your server when you modify this file.
Rails.application.config.action_dispatch.cookies_serializer = :json
\ No newline at end of file
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:password]
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym 'RESTful'
# end
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cookie_store, key: '_rails_4_1_1_session'
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
# end
# Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t 'hello'
#
# In views, this is aliased to just `t`:
#
# <%= t('hello') %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# To learn more, please read the Rails Internationalization guide
# available at http://guides.rubyonrails.org/i18n.html.
en:
hello: "Hello world"
Rails.application.routes.draw do
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
end
# Be sure to restart your server when you modify this file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.
# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.
development:
secret_key_base: 6c17ffa1446409733e3bc5b3250a56dbbfe8fb1a235c966e89344814abca7c25a23647d3eef49d2a7e7751d501b294cc4a3911549441aa9ddffe45a36f40e96c
test:
secret_key_base: 952ea361989ff7bba92aae19f14cbd4ab5c1fe431a0d28420ab1d14593a4b15c905dffdb26f3ab14108c023540fa89ac9364a98fe48e402602ec01159fa64b91
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
class CreateTasks < ActiveRecord::Migration
def change
create_table :tasks do |t|
t.string :content
t.column :status, default: 0
t.timestamps
end
end
end
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140526224112) do
create_table "tasks", force: true do |t|
t.string "content"
t.integer "status"
t.datetime "created_at"
t.datetime "updated_at"
end
end
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
# NOTE: only doing this in development as some production environments (Heroku)
# NOTE: are sensitive to local FS writes, and besides -- it's just not proper
# NOTE: to have a dev-mode tool do its thing in production.
if Rails.env.development?
task :set_annotation_options do
# You can override any of these by setting an environment variable of the
# same name.
Annotate.set_defaults({
'position_in_routes' => "before",
'position_in_class' => "before",
'position_in_test' => "before",
'position_in_fixture' => "before",
'position_in_factory' => "before",
'show_indexes' => "true",
'simple_indexes' => "false",
'model_dir' => "app/models",
'include_version' => "false",
'require' => "",
'exclude_tests' => "false",
'exclude_fixtures' => "false",
'exclude_factories' => "false",
'ignore_model_sub_dir' => "false",
'skip_on_db_migrate' => "false",
'format_bare' => "true",
'format_rdoc' => "false",
'format_markdown' => "false",
'sort' => "false",
'force' => "false",
'trace' => "false",
})
end
Annotate.load_tasks
end
require 'test_helper'
class TaskTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# Add more helper methods to be used by all tests here...
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