datum 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +35 -0
  3. data/Rakefile +38 -0
  4. data/lib/datum/context.rb +55 -0
  5. data/lib/datum/db_tasks.rb +82 -0
  6. data/lib/datum/driver_helper.rb +75 -0
  7. data/lib/datum/enable_notification.rb +27 -0
  8. data/lib/datum/enable_task.rb +118 -0
  9. data/lib/datum/railtie.rb +14 -0
  10. data/lib/datum/version.rb +3 -0
  11. data/lib/datum.rb +101 -0
  12. data/lib/generators/datum/USAGE +0 -0
  13. data/lib/generators/datum/datum_generator.rb +104 -0
  14. data/lib/generators/datum/templates/datum_migration.rb +21 -0
  15. data/lib/generators/datum/templates/datum_model.rb +6 -0
  16. data/lib/tasks/datum.rake +38 -0
  17. data/test/datum_test.rb +17 -0
  18. data/test/dummy/README.rdoc +261 -0
  19. data/test/dummy/Rakefile +7 -0
  20. data/test/dummy/app/assets/javascripts/application.js +15 -0
  21. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  22. data/test/dummy/app/controllers/application_controller.rb +3 -0
  23. data/test/dummy/app/helpers/application_helper.rb +2 -0
  24. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  25. data/test/dummy/config/application.rb +61 -0
  26. data/test/dummy/config/boot.rb +10 -0
  27. data/test/dummy/config/database.example +42 -0
  28. data/test/dummy/config/database.sqlite +25 -0
  29. data/test/dummy/config/database.yml +55 -0
  30. data/test/dummy/config/environment.rb +5 -0
  31. data/test/dummy/config/environments/development.rb +37 -0
  32. data/test/dummy/config/environments/production.rb +67 -0
  33. data/test/dummy/config/environments/test.rb +37 -0
  34. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/test/dummy/config/initializers/inflections.rb +15 -0
  36. data/test/dummy/config/initializers/mime_types.rb +5 -0
  37. data/test/dummy/config/initializers/secret_token.rb +7 -0
  38. data/test/dummy/config/initializers/session_store.rb +8 -0
  39. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  40. data/test/dummy/config/locales/en.yml +5 -0
  41. data/test/dummy/config/routes.rb +58 -0
  42. data/test/dummy/config.ru +4 -0
  43. data/test/dummy/db/schema.rb +16 -0
  44. data/test/dummy/log/development.log +17 -0
  45. data/test/dummy/log/test.log +25 -0
  46. data/test/dummy/public/404.html +26 -0
  47. data/test/dummy/public/422.html +26 -0
  48. data/test/dummy/public/500.html +25 -0
  49. data/test/dummy/public/favicon.ico +0 -0
  50. data/test/dummy/script/rails +6 -0
  51. data/test/dummy/test/test_helper.rb +13 -0
  52. data/test/dummy/test/unit/simple_model_test.rb +7 -0
  53. data/test/test_helper.rb +10 -0
  54. metadata +153 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Tyemill. http://tyemill.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Datum is currently under development and pre-1.0
2
+
3
+ ## Datum
4
+
5
+ Datum is a simple take on Data Driven Testing for Rails. Datum:
6
+
7
+ * Enables a table to drive a test case
8
+ * Quick conversion from data-driven via a database to via a file
9
+ * Dump tables to fixtures for scc storage
10
+ * Load tables from fixtures
11
+ * Generate datum specific migrations and models
12
+
13
+ ## Rails 3
14
+
15
+ Datum is still in development. Currently, we're working with Rails 3.2.6 and Ruby 1.9.3.
16
+
17
+ ### Getting Started
18
+
19
+ Add Datum to your Gemfile:
20
+
21
+ ```ruby
22
+ gem 'datum'
23
+ ```
24
+
25
+ Run the bundle command to install it.
26
+
27
+ After you install Datum and add it to your Gemfile, you need to enable it:
28
+
29
+ ```console
30
+ rake datum:enable
31
+ ```
32
+
33
+ Enable will create several directories in your test directory. It will also prompt you to ask for permission to update your database.yml and application.rb. You MUST review both files even if you have Enable update them for you.
34
+
35
+ When you are finished, you are ready to add Datum migrations and models to your application as needed.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Datum'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,55 @@
1
+
2
+ module Datum
3
+
4
+ class Context
5
+
6
+ def self.initialized?
7
+ return @@initialized
8
+ end
9
+
10
+ def self.continue?
11
+ @@table_data.nil? ? false : (@@table_data.count != 0 ? true : false)
12
+ end
13
+
14
+ protected
15
+
16
+ def self.next_row
17
+ result = nil if @@table_data.nil?
18
+ result = @@table_data.delete_at(0) unless @@table_data.nil?
19
+ @@initialized = false if !result.nil? && @@table_data.count == 0
20
+
21
+ log "next row table_data: #{@@table_data}"
22
+ log "next row result: #{result.attributes}" unless result.nil?
23
+ log "next row initialized: #{@@initialized}"
24
+ return result
25
+ end
26
+
27
+ def self.datum_directory
28
+ return @@directory
29
+ end
30
+
31
+ def self.table_data
32
+ return @@table_data
33
+ end
34
+
35
+ def self.table_data= data
36
+ @@table_data = data
37
+ @@initialized = true if !@@table_data.nil?
38
+ end
39
+
40
+ def self.log msg
41
+ Datum::DriverHelper.log msg
42
+ end
43
+
44
+ @@directory = "#{Rails.env}/lib/datum"
45
+ @@test_directory = "#{Rails.env}/test/lib/datum"
46
+ @@table_data = nil
47
+ @@initialized = false
48
+
49
+ private
50
+
51
+
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,82 @@
1
+
2
+ module Datum
3
+ class DbTasks
4
+ def initialize
5
+ Rails.env = @@datum_environment
6
+ end
7
+
8
+ def create
9
+ Rake::Task['db:create'].invoke()
10
+ end
11
+
12
+ def migrate
13
+ ActiveRecord::Base.establish_connection(Rails.env)
14
+ ActiveRecord::Migrator.migrate "#{@@local_path}/migrate"
15
+ end
16
+
17
+ def drop
18
+ Rake::Task['db:drop'].invoke()
19
+ end
20
+
21
+ # get into the datum fixtures directory, walk the yml, load into db
22
+ def load
23
+ Dir.glob("#{@@local_path}/fixtures/*.yml").entries.each do |entry|
24
+ file_name = entry.to_s.split('/').last.to_s.split('.')[0]
25
+ target_model = file_name.classify.constantize
26
+ data_hash = YAML.load(File.read(entry))
27
+ data_hash.each_value {|value|
28
+ value.delete "id"
29
+ value.delete "created_at"
30
+ value.delete "updated_at"
31
+ target_model.create value
32
+ }
33
+ end
34
+ end
35
+
36
+ # get into datum db, get relevant tables, produce ymls (for sharing)
37
+ # tonyamoyal.com/2009/12/09/
38
+ # converting-table-data-to-yaml-for-testing-in-ruby-on-rails/
39
+ def dump
40
+ sql = "SELECT * FROM %s"
41
+ skip_tables = ["schema_info", "schema_migrations"]
42
+ ActiveRecord::Base.establish_connection(Rails.env)
43
+ tables = (ActiveRecord::Base.connection.tables - skip_tables)
44
+ tables.each do |table_name|
45
+ i = "000"
46
+ File.open("#{@@local_path}/fixtures/#{table_name}.yml",
47
+ 'w') do |file|
48
+ data = ActiveRecord::Base.connection.select_all(sql % table_name)
49
+ file.write data.inject({}) { |hash, record|
50
+ hash["#{table_name}_#{i.succ!}"] = record
51
+ hash}.to_yaml
52
+ end
53
+ end
54
+ end
55
+
56
+ # take Models data, produce a file for use without db
57
+ def localize args
58
+ tasked_model = args[:table].classify.constantize
59
+ data = tasked_model.all
60
+ file_name = args[:table]
61
+ File.open("#{@@local_path}/locals/#{file_name}.rb", 'w') do |f1|
62
+ f1.puts "\n\n#\n# data dump for code access of table #{file_name}"
63
+ f1.puts "#\nmodule #{tasked_model.to_s.pluralize}"
64
+ f1.puts "def self.data\nd = ["
65
+ data.each_with_index {|e, i|
66
+ hash = e.attributes
67
+ hash.each_pair {|key, value|
68
+ new_value = value.to_s
69
+ hash[key] = new_value
70
+ }
71
+ f1.puts "#{hash.to_s},"
72
+ }
73
+ f1.puts "]\nend\nend"
74
+ end
75
+ end
76
+
77
+ private
78
+ @@local_path = "#{Rails.root}/test/lib/datum"
79
+ @@datum_environment = "datum"
80
+
81
+ end
82
+ end
@@ -0,0 +1,75 @@
1
+
2
+ module Datum
3
+
4
+ class DriverHelper
5
+
6
+ def self.load_data table
7
+ context.table_data = load_file_data(table) || load_model_data(table)
8
+ end
9
+
10
+ def self.add_datum_exec_ext init_before_exec, result
11
+ return result if !init_before_exec && !context.initialized?
12
+
13
+ first = !init_before_exec && context.initialized?
14
+ last = init_before_exec && !context.initialized?
15
+
16
+ base = "," if result == "."
17
+ base = "," + result unless base == ","
18
+ base = "[" + base if first
19
+ base += "]" if last
20
+ return base
21
+ end
22
+
23
+ def self.enable_logger
24
+ @@logger = true
25
+ end
26
+
27
+ def self.disable_logger
28
+ @@logger = false
29
+ end
30
+
31
+ protected
32
+ @@logger = false
33
+
34
+ def self.log msg
35
+ Rails.logger.debug "$$ " + msg unless !@@logger
36
+ end
37
+
38
+ def self.load_model_data table
39
+ data = nil
40
+ begin
41
+ driver_method = table.to_s.singularize
42
+ data = driver_method.classify.constantize.all.reverse
43
+ rescue Exception => exc
44
+ log "load_model_data: could not get data from model #{driver_method}"
45
+ log exc
46
+ raise
47
+ "Accessing datum database with table / model #{driver_method} failed."
48
+ end
49
+
50
+ return data
51
+ end
52
+
53
+ def self.load_file_data table
54
+ data = nil
55
+ begin
56
+ require "lib/datum/locals/#{table}"
57
+ cls = driver_method.classify.pluralize.constantize
58
+ data = cls::data.reverse
59
+ data = mock_data data
60
+ rescue Exception => exc
61
+ ## database-driven
62
+ log "load_file_data: file load failed. moving to database load."
63
+ end
64
+
65
+ return data
66
+ end
67
+
68
+ private
69
+
70
+ def self.context
71
+ return Datum::Context
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,27 @@
1
+
2
+ module Datum
3
+ NOTIFICATION =
4
+ "
5
+ ### !!!ADDITIONAL UPDATES REQUIRED!!!
6
+
7
+ Datum requires:
8
+ + application.rb to reference testcase specific models
9
+ + database.yml to contain a datum environment
10
+
11
+ - application.rb should contain:
12
+ config.autoload_paths += %W(\#{Rails.root}/test/lib/datum/models)
13
+
14
+ - database.yml should contain something like:
15
+
16
+ datum:
17
+ adapter: mysql2
18
+ encoding: utf8
19
+ reconnect: false
20
+ database: yourapp_datum
21
+ pool: 5
22
+ username: root
23
+ password:
24
+ socket: /tmp/mysql.sock
25
+
26
+ "
27
+ end
@@ -0,0 +1,118 @@
1
+
2
+ module Datum
3
+ class EnableTask
4
+
5
+ def rock
6
+ puts "\n Enabling Datum Data-Driven Testing Tools."
7
+ create_directories
8
+ notify_check
9
+ update_yml if @@update_yml
10
+ update_app if @@update_app
11
+ puts " Datum enabled.\n "
12
+ end
13
+
14
+ private
15
+ @@application_path = @@info = nil
16
+ @@update_app = @@update_yml = false
17
+ @@datum_drop_path = "test/lib/datum"
18
+ @@datum_model_path = 'config.autoload_paths += %W(#{Rails.root}/' +
19
+ "#{@@datum_drop_path}" + '/models)'
20
+ @@datum_app_scan = "config.autoload_paths.*#{@@datum_drop_path}/models"
21
+ #@@datum_app_scan = "config.autoload_paths.*test\/lib\/datum\/models"
22
+ #@@datum_drop_path.gsub(Regexp.new("\\/"), "\\/")
23
+ #"config.autoload_paths.*#{encoded_path}\/models"
24
+
25
+ def create_directories
26
+ ["#{@@datum_drop_path}/fixtures", "#{@@datum_drop_path}/locals",
27
+ "#{@@datum_drop_path}/migrate", "#{@@datum_drop_path}/models"].each {
28
+ |path| FileUtils.mkdir_p(path) if !File::directory?(path)}
29
+
30
+ puts " Datum directories created."
31
+ end
32
+
33
+ def notify_check
34
+ @@update_yml = need_yml?
35
+ @@update_app = need_app?
36
+
37
+ notify unless !@@update_yml && !@@update_app
38
+ end
39
+
40
+ def notify
41
+ require "datum/enable_notification"
42
+ puts "#{Datum::NOTIFICATION}"
43
+ puts " Files that may need updates: "
44
+ puts " database.yml" if @@update_yml
45
+ puts " application.rb" if @@update_app
46
+ puts "\n>>>>>>>>>>>>>>>> Attempt updates for you? y/n"
47
+ continue = STDIN.gets.chomp
48
+ unless continue == 'y' || continue == 'yes'
49
+ puts "\n Files must be updated manually to fully enable Datum\n "
50
+ exit!
51
+ end
52
+ end
53
+
54
+ def update_yml
55
+ app_name = Rails.root.to_s.split("/").last
56
+ target_hash = @@info["test"] ? @@info["test"] : @@info["development"]
57
+
58
+ if target_hash.nil?
59
+ puts " Can't update database.yml without a pre-existing"
60
+ puts " test or development segment."
61
+ puts "###### !!!! Please update database.yml manually !!!! ######\n "
62
+ return
63
+ end
64
+
65
+ File.open(Rails.root.join("config/database.yml"), 'a') do |f1|
66
+ f1.puts "\n\n#\n# database entry for data-driven testing.\n#"
67
+ f1.puts "datum:"
68
+ target_hash.each_pair {|key, value|
69
+ f1.puts " #{key}: #{value}" unless key == "database"
70
+ f1.puts " database: #{app_name}_datum" if key == "database"
71
+ }
72
+ end
73
+
74
+ puts " database.yml updated with datum entry"
75
+ end
76
+
77
+ def update_app
78
+ FileUtils.mkdir_p("tmp")
79
+ tmp_path = "tmp/app.tmp"
80
+ tempfile = File.open(tmp_path, 'w')
81
+ readfile = open_app_file
82
+
83
+ readfile.each do |line|
84
+ tempfile << line
85
+ if line.strip == "class Application < Rails::Application"
86
+ tempfile << "\n # Added as part of datum install, enables access to datum specific models\n"
87
+ tempfile << " #{@@datum_model_path}\n\n"
88
+ end
89
+ end
90
+
91
+ readfile.close
92
+ tempfile.close
93
+ FileUtils.mv(tmp_path, @@application_path)
94
+
95
+ puts " application.rb updated with datum model reference"
96
+ end
97
+
98
+ def need_yml?
99
+ @@info = YAML::load(IO.read(Rails.root.join("config/database.yml")))
100
+ return true unless @@info["datum"]
101
+ return false
102
+ end
103
+
104
+ def need_app?
105
+ pattern = Regexp.new "#{@@datum_app_scan}"
106
+ readfile = open_app_file
107
+ readfile.each do |line|
108
+ return false if line.scan(pattern).length != 0
109
+ end
110
+ return true
111
+ end
112
+
113
+ def open_app_file
114
+ @@application_path = Rails.root.join("config/application.rb")
115
+ return File.new(@@application_path)
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,14 @@
1
+
2
+ module Datum
3
+ require 'rails'
4
+ # require 'active_support'
5
+
6
+ class Railtie < Rails::Railtie
7
+ rake_tasks do
8
+ load "tasks/datum.rake"
9
+ end
10
+ # initializer 'Rails logger' do
11
+ # Datum.logger = Rails.logger
12
+ # end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Datum
2
+ VERSION = "0.8.0"
3
+ end
data/lib/datum.rb ADDED
@@ -0,0 +1,101 @@
1
+ # datum helps data-driven testing.
2
+ #
3
+ # Author:: Gabriel Marius, Tyemill
4
+ # Copyright:: Copyright (c) 2012 Tyemill, llc.
5
+ # License:: MIT License (http://www.opensource.org/licenses/mit-license.php)
6
+
7
+ require 'datum/railtie'
8
+ require 'datum/driver_helper'
9
+ require 'datum/context'
10
+ #require 'test/unit'
11
+
12
+ module Datum
13
+ ActiveSupport::TestCase.class_eval do
14
+ alias_method :original_initialize, :initialize
15
+
16
+
17
+ def initialize(tst)
18
+ log NEW_TST
19
+ original_initialize tst
20
+ end
21
+
22
+ def drive_with table
23
+ datum_helper::load_data table if !datum_context::initialized?
24
+ @@driver_row = datum_context.next_row
25
+ log "drive_with table: #{table}"
26
+ log "drive_with row: #{@@driver_row.attributes}" unless @@driver_row.nil?
27
+ end
28
+
29
+ def datum
30
+ return @@driver_row
31
+ end
32
+
33
+ private
34
+ @@driver_row = nil
35
+ NEW_TST = "@@@ N E W T S T C A S E @@@@@@@@@@@@@@@@@@@@@@@@@@@@"
36
+ def log msg
37
+ datum_helper.log msg
38
+ end
39
+
40
+ def datum_helper
41
+ return Datum::DriverHelper
42
+ end
43
+
44
+ def datum_context
45
+ return Datum::Context
46
+ end
47
+
48
+ end
49
+
50
+ MiniTest::Unit.class_eval do
51
+ alias_method :original__run_suite, :_run_suite
52
+
53
+ def _run_suite suite, type
54
+ header = "#{type}_suite_header"
55
+ puts send(header, suite) if respond_to? header
56
+
57
+ filter = options[:filter] || '/./'
58
+ filter = Regexp.new $1 if filter =~ /\/(.*)\//
59
+
60
+ testcases = suite.send("#{type}_methods").grep(filter)
61
+ assertions = []
62
+ p_test = nil
63
+ testcases.map { |test_case|
64
+ while datum_context::continue? || p_test != test_case do
65
+ __runner assertions, test_case, suite
66
+ p_test = test_case
67
+ end
68
+ }
69
+ return assertions.size, assertions.inject(0) { |sum, n| sum + n }
70
+ end
71
+
72
+ def __runner(assertions, test_case, suite)
73
+ testcase_result = inner_runner(test_case, suite)
74
+ assertions.push testcase_result
75
+ end
76
+
77
+ def inner_runner(method, suite)
78
+ inst = suite.new method
79
+ inst._assertions = 0
80
+ print "#{suite}##{method} = " if @verbose
81
+ @start_time = Time.now
82
+ datum_init = datum_context::initialized?
83
+ result = inst.run self
84
+ time = Time.now - @start_time
85
+ print "%.2f s = " % time if @verbose
86
+ result = Datum::DriverHelper::add_datum_exec_ext datum_init, result
87
+ print result
88
+ puts if @verbose
89
+
90
+ inst._assertions
91
+ end
92
+
93
+ private
94
+ def datum_context
95
+ return Datum::Context
96
+ end
97
+
98
+ end
99
+
100
+
101
+ end
File without changes
@@ -0,0 +1,104 @@
1
+ require 'rails/generators/migration'
2
+ require 'rails/generators/generated_attribute'
3
+
4
+ # Generator code was modified from https://github.com/ryanb/nifty-generators/
5
+ # Nifty Generators is Copyright (c) 2011 Ryan Bates and distributed via the
6
+ # MIT License
7
+ class DatumGenerator < Rails::Generators::Base
8
+ include Rails::Generators::Migration
9
+ no_tasks { attr_accessor :scaffold_name, :model_attributes}
10
+ source_root File.expand_path('../templates', __FILE__)
11
+
12
+ argument :scaffold_name, :type => :string, :required => true, :banner => 'ModelName'
13
+ argument :args_for_m, :type => :array, :default => [], :banner => 'model:attributes'
14
+
15
+ class_option :skip_migration,
16
+ :desc => 'Don\'t generate migration file for model.', :type => :boolean
17
+
18
+ class_option :skip_model,
19
+ :desc => 'Don\'t generate a model or migration file.', :type => :boolean
20
+
21
+ def initialize(*args, &block)
22
+ super
23
+ print_usage unless scaffold_name.underscore =~ /^[a-z][a-z0-9_\/]+$/
24
+
25
+ @datum_path = "test/lib/datum"
26
+ @model_attributes = []
27
+ @skip_model = options.skip_model?
28
+
29
+ args_for_m.each do |arg|
30
+ if arg.include?(':')
31
+ @model_attributes << Rails::Generators::GeneratedAttribute.new(*arg.split(':'))
32
+ end
33
+ end
34
+
35
+ @model_attributes.uniq!
36
+
37
+ if @model_attributes.empty?
38
+ @skip_model = true # skip model if no attributes
39
+ if model_exists?
40
+ model_columns_for_attributes.each do |column|
41
+ @model_attributes << Rails::Generators::GeneratedAttribute.new(
42
+ column.name.to_s, column.type.to_s)
43
+ end
44
+ else
45
+ @model_attributes << Rails::Generators::GeneratedAttribute.new(
46
+ 'name', 'string')
47
+ end
48
+ end
49
+ end
50
+
51
+ def create_model
52
+ unless @skip_model
53
+ template 'datum_model.rb', "#{@datum_path}/models/#{model_path}.rb"
54
+ end
55
+ end
56
+ def create_migration
57
+ unless @skip_model || options.skip_migration?
58
+ migration_template 'datum_migration.rb',
59
+ "#{@datum_path}/migrate/create_#{model_path.pluralize.gsub('/', '_')}.rb"
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def plural_name
66
+ scaffold_name.underscore.pluralize
67
+ end
68
+
69
+ def plural_class_name
70
+ plural_name.camelize
71
+ end
72
+
73
+ def table_name
74
+ if scaffold_name.include?('::') && @namespace_model
75
+ plural_name.gsub('/', '_')
76
+ end
77
+ end
78
+
79
+ def class_name
80
+ scaffold_name.split('::').last.camelize
81
+ end
82
+
83
+ def model_path
84
+ class_name.underscore
85
+ end
86
+
87
+ def model_exists?
88
+ File.exist? destination_path("#{@datum_path}/models/#{singular_name}.rb")
89
+ end
90
+
91
+ def destination_path(path)
92
+ File.join(destination_root, path)
93
+ end
94
+
95
+ # FIXME: Should be proxied to ActiveRecord::Generators::Base
96
+ # Implement the required interface for Rails::Generators::Migration.
97
+ def self.next_migration_number(dirname) #:nodoc:
98
+ if ActiveRecord::Base.timestamped_migrations
99
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
100
+ else
101
+ "%.3d" % (current_migration_number(dirname) + 1)
102
+ end
103
+ end
104
+ end