mdd 3.0.6 → 3.0.7

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 (34) hide show
  1. data/app/controllers/mdwa/requirements_controller.rb +4 -1
  2. data/lib/generators/mdwa/association/association_generator.rb +17 -10
  3. data/lib/generators/mdwa/code/code_generator.rb +9 -1
  4. data/lib/generators/mdwa/{template/templates/views → templates/templates/actions}/view.custom.erb +0 -0
  5. data/lib/generators/mdwa/{template/templates/views → templates/templates/actions}/view.html.erb +0 -0
  6. data/lib/generators/mdwa/{template/templates/views → templates/templates/actions}/view.js.erb +0 -0
  7. data/lib/generators/mdwa/{template/templates/views → templates/templates/actions}/view.json.erb +0 -0
  8. data/lib/generators/mdwa/templates/templates/general/routes.rb +3 -0
  9. data/lib/generators/mdwa/templates/templates/scaffold/controller.rb +150 -0
  10. data/lib/generators/mdwa/templates/templates/scaffold/helper.rb +3 -0
  11. data/lib/generators/mdwa/templates/templates/scaffold/model.rb +50 -0
  12. data/lib/generators/mdwa/templates/templates/scaffold/views/_form.html.erb +23 -0
  13. data/lib/generators/mdwa/templates/templates/scaffold/views/_form_fields.html.erb +45 -0
  14. data/lib/generators/mdwa/templates/templates/scaffold/views/_list.html.erb +47 -0
  15. data/lib/generators/mdwa/templates/templates/scaffold/views/create.js.erb +8 -0
  16. data/lib/generators/mdwa/templates/templates/scaffold/views/destroy.js.erb +3 -0
  17. data/lib/generators/mdwa/templates/templates/scaffold/views/edit.html.erb +10 -0
  18. data/lib/generators/mdwa/templates/templates/scaffold/views/index.html.erb +17 -0
  19. data/lib/generators/mdwa/templates/templates/scaffold/views/index.js.erb +2 -0
  20. data/lib/generators/mdwa/templates/templates/scaffold/views/new.html.erb +10 -0
  21. data/lib/generators/mdwa/templates/templates/scaffold/views/show.html.erb +31 -0
  22. data/lib/generators/mdwa/templates/templates/scaffold/views/update.js.erb +13 -0
  23. data/lib/generators/mdwa/templates/templates_generator.rb +144 -0
  24. data/lib/generators/mdwa/transform/templates/changes_migration.rb +16 -0
  25. data/lib/generators/mdwa/transform/transform_generator.rb +258 -61
  26. data/lib/generators/mdwa/user_scaffold/user_scaffold_generator.rb +32 -14
  27. data/lib/mdwa/dsl/action.rb +10 -1
  28. data/lib/mdwa/dsl/entity.rb +9 -3
  29. data/lib/mdwa/dsl/entity_association.rb +21 -0
  30. data/lib/mdwa/dsl/requirements.rb +4 -0
  31. data/lib/mdwa/generators/model_association.rb +9 -3
  32. data/lib/mdwa/version.rb +1 -1
  33. metadata +25 -9
  34. data/lib/generators/mdwa/template/template_generator.rb +0 -40
@@ -0,0 +1,144 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'rails/generators'
4
+ require 'rails/generators/migration'
5
+
6
+ require 'mdwa/dsl'
7
+
8
+ module Mdwa
9
+ module Generators
10
+ class TemplatesGenerator < Rails::Generators::Base
11
+
12
+ include Rails::Generators::Migration
13
+
14
+ source_root File.expand_path("../templates", __FILE__)
15
+
16
+ attr_accessor :entities
17
+
18
+ #
19
+ # Constructor
20
+ # Require all entities to load the DSL of the application
21
+ def initialize(*args, &block)
22
+ super
23
+
24
+ # include files with entities
25
+ # select entities that will be generated
26
+ inside Rails.root do
27
+ require_all MDWA::DSL::STRUCTURAL_PATH unless Dir.glob("#{MDWA::DSL::STRUCTURAL_PATH}/*.rb").count.zero?
28
+ end
29
+ @entities = MDWA::DSL.entities.all
30
+ end
31
+
32
+
33
+ def general_files
34
+ template 'general/routes.rb', "#{MDWA::DSL::TEMPLATES_PATH}routes.rb"
35
+ end
36
+
37
+ def entities_scaffold
38
+
39
+ @entities.each do |entity|
40
+
41
+ model = entity.generator_model
42
+
43
+ puts '--------------------------------------'
44
+ puts "- Code for: #{entity.name} -"
45
+ puts '--------------------------------------'
46
+
47
+ copy_with_header 'scaffold/controller.rb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}controller.rb", entity.name
48
+ copy_with_header 'scaffold/helper.rb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}helper.rb", entity.name
49
+ copy_with_header 'scaffold/model.rb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}model.rb", entity.name
50
+
51
+ # views
52
+ copy_with_header 'scaffold/views/_form_fields.html.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/_form_fields.html.erb", entity.name
53
+ copy_with_header 'scaffold/views/_form.html.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/_form.html.erb", entity.name
54
+ copy_with_header 'scaffold/views/_list.html.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/_list.html.erb", entity.name
55
+ copy_with_header 'scaffold/views/create.js.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/create.js.erb", entity.name
56
+ copy_with_header 'scaffold/views/destroy.js.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/destroy.js.erb", entity.name
57
+ copy_with_header 'scaffold/views/edit.html.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/edit.html.erb", entity.name
58
+ copy_with_header 'scaffold/views/index.html.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/index.html.erb", entity.name
59
+ copy_with_header 'scaffold/views/index.js.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/index.js.erb", entity.name
60
+ copy_with_header 'scaffold/views/new.html.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/new.html.erb", entity.name
61
+ copy_with_header 'scaffold/views/show.html.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/show.html.erb", entity.name
62
+ copy_with_header 'scaffold/views/update.js.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/update.js.erb", entity.name
63
+ end
64
+ end
65
+
66
+
67
+ def entity_actions
68
+
69
+ puts '--------------------------------------'
70
+ puts "- Generating actions -"
71
+ puts '--------------------------------------'
72
+
73
+ @entities.each do |entity|
74
+ # next iteration if entity doesn't have specifications
75
+ next if entity.actions.actions.count.zero?
76
+
77
+ model = entity.generator_model
78
+
79
+ path_to_controller = "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}controller.rb"
80
+ controller_string = File.read("#{Rails.root}/#{path_to_controller}")
81
+
82
+ # hooks for code generations
83
+ controller_hook = '#===controller_init==='
84
+ test_hook = '#===test_init==='
85
+
86
+ # insert in controller
87
+ insert_into_file path_to_controller, :after => controller_hook do
88
+ actions = []
89
+ entity.actions.generate_controller.each do |action_name, generation_string|
90
+ # write the generated code only if it is not declared in the controller
91
+ actions << "\n\n#{generation_string}" unless controller_string.include? "def #{action_name}"
92
+ end
93
+ actions.join
94
+ end
95
+
96
+ # generate the corresponding files
97
+ entity.actions.actions.values.select{ |a| !a.resource? }.each do |action|
98
+ action.template_names.each do |request, file_name|
99
+ case request.to_sym
100
+ when :modalbox, :html
101
+ copy_with_header 'actions/view.html.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/#{file_name}", entity unless File.exist?("#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/views/#{file_name}")
102
+ when :ajax
103
+ copy_with_header 'actions/view.js.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/#{file_name}", entity unless File.exist?("#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/views/#{file_name}")
104
+ when :ajax_js
105
+ copy_with_header 'actions/view.json.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/#{file_name}", entity unless File.exist?("#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/views/#{file_name}")
106
+ else
107
+ copy_with_header 'actions/view.custom.erb', "#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/#{model.space + '/'}views/#{file_name}", entity unless File.exist?("#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/views/#{file_name}")
108
+ end
109
+ end
110
+ end
111
+
112
+ # inject routes testing
113
+ # if File.exist?(Rails.root + "/spec/routing/#{model.space}/#{model.plural_name}_routing_spec.rb")
114
+ # insert_into_file "spec/routing/#{model.space}/#{model.plural_name}_routing_spec.rb", :after => 'describe "routing" do' do
115
+ # routes = []
116
+ # entity.actions.actions.values.select {|a| !a.resource}.each do |action|
117
+ # routes << "\n\n\t\tit 'routes to ##{action.name}' do"
118
+ # routes << "\n\t\t\t#{action.method.to_s}('#{action.entity.generator_model.to_route_url}/#{'1/' if action.member?}#{action.name}').should route_to('#{action.entity.generator_model.to_route_url}##{action.name}' #{', :id => "1"' if action.member?})"
119
+ # routes << "\n\t\tend"
120
+ # end
121
+ # routes.join
122
+ # end
123
+ # end
124
+
125
+ end # @entities loop
126
+
127
+ end
128
+
129
+ def tests
130
+ end
131
+
132
+
133
+ private
134
+
135
+ def copy_with_header(source, destination, entity)
136
+ if !File.exist?(Rails.root + destination) or options.force
137
+ copy_file source, destination
138
+ gsub_file destination, '===entity_code===', "<%- \n@entity = MDWA::DSL.entity('#{entity}') \n@model = @entity.generator_model \n-%>", {:verbose => false}
139
+ end
140
+ end
141
+
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class Alter<%= @entities.select{|e| e.resource?}.collect{|e| e.file_name.camelize}.join('') %><%= @random_migration_key %> < ActiveRecord::Migration
3
+
4
+ def self.up
5
+ <%- @changes.each do |change| -%>
6
+ <%= change[:type] %> :<%= MDWA::Generators::Model.new(change[:entity].model_name).plural_name %>, :<%= change[:column] %> <%= ", :#{change[:attr_type]}" unless change[:attr_type].blank? or change[:type] == 'remove_column' %>
7
+ <%- end -%>
8
+ end
9
+
10
+ def self.down
11
+ <%- @changes.each do |change| -%>
12
+ <%= inverse_migration_type change[:type] %> :<%= MDWA::Generators::Model.new(change[:entity].model_name).plural_name %>, :<%= change[:column] %> <%= ", :#{change[:attr_type]}" if inverse_migration_type(change[:type]) == 'add_column' %> <%= ", :#{change[:from]}" unless change[:from].blank? %>
13
+ <%- end -%>
14
+ end
15
+
16
+ end
@@ -1,102 +1,241 @@
1
1
  require 'erb'
2
2
  require 'mdwa/dsl'
3
3
 
4
+ require 'rails/generators'
5
+ require 'rails/generators/migration'
6
+
7
+
4
8
  module Mdwa
5
9
  module Generators
6
10
 
7
11
  class TransformGenerator < Rails::Generators::Base
8
12
 
13
+ include Rails::Generators::Migration
14
+
15
+ attr_accessor :pending_migrations
16
+
17
+ argument :entities, :type => :array, :banner => 'Entities to transform', :default => []
18
+
19
+ source_root File.expand_path("../templates", __FILE__)
20
+
9
21
  def initialize(*args, &block)
10
22
  super
11
23
 
24
+ # control if there are any migrations to execute
25
+ @pending_migrations = false
26
+
12
27
  # include files with entities
13
- # select entities that will be generated
14
28
  inside Rails.root do
15
29
  require_all MDWA::DSL::STRUCTURAL_PATH unless Dir.glob("#{MDWA::DSL::STRUCTURAL_PATH}/*.rb").count.zero?
16
30
  end
17
- @entities = MDWA::DSL.entities.all
18
-
19
- end
20
-
21
- def generate_model
22
- @project_entity = MDWA::DSL.entity('Project')
23
- generator_model = @project_entity.generator_model
24
-
25
- mdwa_template "#{@project_entity.file_name}/model.rb", "app/models/#{generator_model.space}/#{generator_model.singular_name}.rb"
26
- end
27
-
28
- def generate_controller
29
- @project_entity = MDWA::DSL.entity('Project')
30
- generator_model = @project_entity.generator_model
31
+ # select entities that will be generated
32
+ if entities.count.zero?
33
+ @entities = MDWA::DSL.entities.all
34
+ else
35
+ @entities = entities.collect{ |e| MDWA::DSL.entity(e) }
36
+ end
31
37
 
32
- mdwa_template "#{@project_entity.file_name}/controller.rb", "app/controllers/#{generator_model.space}/#{generator_model.plural_name}_controller.rb"
38
+ # entity changes and migrations
39
+ @changes = []
40
+ @random_migration_key = rand.to_s.gsub('.','').to_i
33
41
  end
34
42
 
35
- def generate_views
36
- @project_entity = MDWA::DSL.entity('Project')
37
- generator_model = @project_entity.generator_model
43
+ def generate_model_controller_helper_views
44
+ @entities.each do |entity|
45
+ generator_model = entity.generator_model
46
+ mdwa_template "#{entity.file_name}/model.rb", "app/models/#{generator_model.space}/#{generator_model.singular_name}.rb"
47
+ mdwa_template "#{entity.file_name}/helper.rb", "app/controllers/#{generator_model.space}/#{generator_model.plural_name}_helper.rb"
48
+ mdwa_template "#{entity.file_name}/controller.rb", "app/controllers/#{generator_model.space}/#{generator_model.plural_name}_controller.rb"
38
49
 
39
- mdwa_template "#{@project_entity.file_name}/views/edit.html.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/edit.html.erb"
40
- mdwa_template "#{@project_entity.file_name}/views/index.html.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/index.html.erb"
41
- mdwa_template "#{@project_entity.file_name}/views/index.js.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/index.js.erb"
42
- mdwa_template "#{@project_entity.file_name}/views/new.html.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/new.html.erb"
43
- mdwa_template "#{@project_entity.file_name}/views/show.html.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/show.html.erb"
44
- mdwa_template "#{@project_entity.file_name}/views/_form.html.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/_form.html.erb"
45
- mdwa_template "#{@project_entity.file_name}/views/_form_fields.html.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/_form_fields.html.erb"
46
- mdwa_template "#{@project_entity.file_name}/views/_list.html.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/_#{generator_model.plural_name}.html.erb"
47
-
48
- if @project_entity.ajax?
49
- mdwa_template "#{@project_entity.file_name}/views/create.js.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/create.js.erb"
50
- mdwa_template "#{@project_entity.file_name}/views/update.js.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/update.js.erb"
51
- mdwa_template "#{@project_entity.file_name}/views/destroy.js.erb", "app/views/#{generator_model.space}/#{generator_model.plural_name}/destroy.js.erb"
50
+ Dir.glob("#{Rails.root}/#{MDWA::DSL::TEMPLATES_PATH}#{entity.file_name}/views/*").each do |file|
51
+ file_name = File.basename(file)
52
+ mdwa_template "#{entity.file_name}/views/#{file_name}", "app/views/#{generator_model.space}/#{generator_model.plural_name}/#{file_name}"
53
+ end
52
54
  end
53
55
  end
54
56
 
55
57
  def generate_routes
56
- @project_entity = MDWA::DSL.entity('Project')
57
- generator_model = @project_entity.generator_model
58
58
 
59
59
  route 'mdwa_router(self)'
60
- append_to_file 'config/routes.rb', "require File.expand_path('../../app/mdwa/templates/routes.rb', __FILE__)"
60
+ path_to_routes = 'app/mdwa/templates/routes.rb'
61
+ insert_into_file 'config/routes.rb', "load File.expand_path('../../#{path_to_routes}', __FILE__)\n\n", :before => /.+::Application\.routes\.draw do(?:\s*\|map\|)?\s*$/
62
+
63
+ # clear routes file contents
64
+ File.truncate(path_to_routes, 0)
65
+ append_file path_to_routes, "def mdwa_router(router)\n\nend"
61
66
 
62
- insert_into_file path_to_routes, :after => "controller :#{generator_model.plural_name} do" do
63
- routes = []
64
- @project_entity.actions.generate_routes.each do |action_name, generation_string|
65
- routes << "\n\t\t\t#{generation_string}"
67
+ @entities.each do |entity|
68
+ generator_model = entity.generator_model
69
+
70
+ # inject scaffold code
71
+ inject_into_file path_to_routes, :after => "def mdwa_router(router)\n" do
72
+ route_str = []
73
+ route_str << "\n\tnamespace :#{generator_model.space} do" if generator_model.namespace?
74
+ route_str << "\t\tcontroller :#{generator_model.plural_name} do"
75
+ route_str << "\t\tend"
76
+ route_str << "\t\tresources :#{generator_model.plural_name}"
77
+ route_str << "\tend\n" if generator_model.namespace?
78
+
79
+ route_str.join "\n"
80
+ end
81
+
82
+ # inject specific actions
83
+ inject_into_file path_to_routes, :after => "controller :#{generator_model.plural_name} do" do
84
+ routes = []
85
+ entity.actions.generate_routes.each do |action_name, generation_string|
86
+ routes << "\n\t#{generation_string}"
87
+ end
88
+ routes.join
66
89
  end
67
- routes.join
68
90
  end
69
91
  end
70
92
 
71
93
  def generate_locales
94
+
95
+ locales_file = 'config/locales/mdwa_model_specific.en.yml'
96
+ locales_content = File.read(locales_file)
97
+ # make sure the file exist
98
+ create_file locales_file unless File.exist?(Rails.root + locales_file)
99
+
100
+ @entities.each do |entity|
101
+ model = entity.generator_model
102
+ if !locales_content.include?( " #{model.plural_name}:" )
103
+ append_file locales_file, :after => "en:\n" do
104
+ lines = []
105
+ lines << " #{model.plural_name}:"
106
+ lines << " create_success: \"#{model.singular_name.humanize} created.\""
107
+ lines << " update_success: \"#{model.singular_name.humanize} updated.\""
108
+ lines << " destroy_success: \"#{model.singular_name.humanize} destroyed.\""
109
+ lines << " index_title: \"#{model.plural_name.humanize}\""
110
+ lines << " show_title: \"#{model.singular_name.humanize}\""
111
+ lines << " new_title: \"New #{model.singular_name.humanize}\""
112
+ lines << " edit_title: \"Edit #{model.singular_name.humanize}\""
113
+ model.attributes.each do |attr|
114
+ lines << " index_#{attr.name}: \"#{attr.name.humanize}\""
115
+ lines << " show_#{attr.name}: \"#{attr.name.humanize}\""
116
+ end
117
+ model.associations.each do |assoc|
118
+ if assoc.belongs_to? or assoc.nested_one? or assoc.has_one?
119
+ lines << " index_#{assoc.model2.singular_name}: \"#{assoc.model2.singular_name.humanize}\""
120
+ lines << " show_#{assoc.model2.singular_name}: \"#{assoc.model2.singular_name.humanize}\""
121
+ else
122
+ lines << " index_#{assoc.model2.singular_name}: \"#{assoc.model2.plural_name.humanize}\""
123
+ lines << " show_#{assoc.model2.singular_name}: \"#{assoc.model2.plural_name.humanize}\""
124
+ end
125
+ end
126
+ lines << "\n"
127
+ lines.join("\n")
128
+ end
129
+ end
130
+
131
+ end # @entities loop
132
+
72
133
  end
73
134
 
74
- def generate_migration
75
- @project_entity = MDWA::DSL.entity('Project')
76
- generator_model = @project_entity.generator_model
77
-
78
- migration_string = []
79
- # create table
80
- migration_string << "\n\tdef self.up"
81
- migration_string << "\t\tcreate_table :#{generator_model.plural_name} do |t|"
82
- generator_model.simple_attributes.each do |attr|
83
- migration_string << "\t\t\tt.#{attr.migration_field} :#{attr.name}"
84
- end
85
- migration_string << "\t\t\tt.timestamps"
86
- migration_string << "\t\tend\n\tend"
87
-
88
- # drop table
89
- migration_string << "\n\tdef self.down"
90
- migration_string << "\t\tdrop_table :#{generator_model.plural_name}"
91
- migration_string << "\tend"
135
+ def generate_migrations
136
+
137
+ @entities.each do |entity|
138
+ # if it's not a resource, ignore
139
+ next unless entity.resource?
140
+
141
+ # if model does not exist, should generate scaffold
142
+ begin
143
+ model_class = entity.generator_model.model_class
144
+ rescue
145
+ model_class = nil
146
+ end
147
+
148
+ # if is a new scaffold, generate migration for scaffold
149
+ if (model_class.nil? or !model_class.table_exists?) and !entity.user?
150
+ migration_for_entity(entity)
151
+ next
152
+ end
153
+
154
+ # generate new fields for users
155
+ if entity.user?
156
+ generation_string = "#{entity.generate} --only_diff_migration --skip_rake_migrate --skip-questions #{'--force' if options.force}"
157
+ generate generation_string
158
+ end
159
+
160
+ end # @entities loop
161
+ end
162
+
163
+
164
+ def generate_changes_in_attributes
92
165
 
93
- migration_name = "create_#{generator_model.plural_name}"
94
- migration_from_string(migration_name, migration_string.join("\n"))
166
+ @entities.each do |entity|
167
+ # do not generate migrations for users changes
168
+ next if entity.user?
169
+ # if it's not a resource, ignore
170
+ next unless entity.resource?
171
+
172
+ # if model does not exist, should generate scaffold
173
+ begin
174
+ model_class = entity.generator_model.model_class
175
+ rescue
176
+ model_class = nil
177
+ end
178
+
179
+ # if table is not created yet, ignore
180
+ next unless model_class.table_exists?
181
+
182
+ # search for changes in this entity
183
+ model_class.columns.each do |column|
184
+
185
+ # ignore rails default columns and attributes used in associations
186
+ next if column.name == 'id' or column.name == 'created_at' or column.name == 'updated_at' or column.name.end_with? '_id'
187
+
188
+ entity_attribute = entity.attributes[column.name]
189
+ # model attribute exists, but not in entity -> was erased
190
+ if entity_attribute.nil?
191
+ @changes << {:entity => entity, :type => 'remove_column', :column => column.name, :attr_type => column.type}
192
+ # attribute exists in model and entity, but changed type
193
+ elsif entity_attribute.type.to_sym != column.type.to_sym
194
+ next if entity_attribute.type.to_sym == :file or entity_attribute.type.to_sym == :password
195
+ @changes << {:entity => entity, :type => 'change_column', :column => column.name, :attr_type => entity_attribute.type, :from => column.type}
196
+ end
197
+ end
198
+
199
+ # new attributes
200
+ # no column with that name -> column must be added
201
+ entity.attributes.each do |key, attr|
202
+ if model_class.columns.select {|c| c.name == attr.name}.count.zero?
203
+ @changes << {:entity => entity, :type => 'add_column', :column => attr.name, :attr_type => attr.type}
204
+ end
205
+ end
206
+
207
+ # new foreign keys
208
+ # belongs_to and nested_one associations that are in the entity, but not database
209
+ entity.generator_model.associations.select{|a| a.belongs_to? or a.nested_one?}.each do |assoc|
210
+ if model_class.columns.select{|c| c.name == assoc.model2.singular_name.foreign_key}.count.zero?
211
+ @changes << {:entity => entity, :type => 'add_column', :column => assoc.model2.name.foreign_key, :attr_type => 'integer'}
212
+ end
213
+ end
214
+
215
+ end # @entities loop
95
216
 
96
- rake('db:migrate') if yes?('Run rake db:migrate')
217
+ # generate changed code
218
+ unless @changes.empty?
219
+ migration_template 'changes_migration.rb', "db/migrate/alter_#{@entities.select{|e| e.resource?}.collect{|e| e.file_name}.join('_')}#{@random_migration_key}.rb"
220
+ @pending_migrations = true
221
+ end
97
222
 
98
223
  end
99
224
 
225
+ #
226
+ # Search for many to many tables.
227
+ def many_to_many_tables
228
+ @entities.each do |entity|
229
+ entity.generator_model.associations.select{|a| a.has_and_belongs_to_many?}.each do |association|
230
+ generate "mdwa:association #{association.model1.singular_name} has_and_belongs_to_many #{association.model2.singular_name} --skip-models"
231
+ end
232
+ end
233
+ end
234
+
235
+ def run_rake_migrate
236
+ rake('db:migrate') if @pending_migrations and yes?('Run rake db:migrate')
237
+ end
238
+
100
239
  def generate_tests
101
240
  end
102
241
 
@@ -109,6 +248,47 @@ module Mdwa
109
248
  create_file "#{Rails.root}/#{file_to_write}", erb.result, :force => true
110
249
  end
111
250
 
251
+
252
+ def migration_for_entity(entity)
253
+ # ignores user
254
+ return nil if entity.user?
255
+
256
+ generator_model = entity.generator_model
257
+
258
+ migration_string = []
259
+ # create table
260
+ migration_string << "\n\tdef self.up"
261
+ migration_string << "\t\tcreate_table :#{generator_model.plural_name} do |t|"
262
+ generator_model.attributes.each do |attr|
263
+ migration_string << "\t\t\tt.#{attr.migration_field} :#{attr.name}"
264
+ end
265
+ generator_model.associations.each do |assoc|
266
+ if assoc.belongs_to? or assoc.nested_one?
267
+ migration_string << "\t\t\tt.integer :#{assoc.model2.singular_name.foreign_key}"
268
+ end
269
+ end
270
+ migration_string << "\t\t\tt.timestamps"
271
+ migration_string << "\t\tend"
272
+ generator_model.associations.each do |assoc|
273
+ if assoc.belongs_to? or assoc.nested_one?
274
+ migration_string << "\t\tadd_index :#{assoc.model1.plural_name}, :#{assoc.model2.singular_name.foreign_key}"
275
+ end
276
+ end
277
+ migration_string << "\n\tend"
278
+
279
+ # drop table
280
+ migration_string << "\n\tdef self.down"
281
+ migration_string << "\t\tdrop_table :#{generator_model.plural_name}"
282
+ migration_string << "\tend"
283
+
284
+ migration_name = "create_#{generator_model.plural_name}"
285
+ migration_from_string(migration_name, migration_string.join("\n"))
286
+
287
+ sleep 1 # aguarda 1 seg para trocar o timestamp
288
+
289
+ @pending_migrations = true
290
+ end
291
+
112
292
  def migration_from_string(file_name, migration_string)
113
293
 
114
294
  # migration number
@@ -123,6 +303,23 @@ module Mdwa
123
303
  create_file "#{Rails.root}/db/migrate/#{@migration_number}_#{file_name}.rb", migration_string
124
304
 
125
305
  end
306
+
307
+ def inverse_migration_type(type)
308
+ case type.to_sym
309
+ when :add_column then 'remove_column'
310
+ when :remove_column then 'add_column'
311
+ when :change_column then 'change_column'
312
+ end
313
+ end
314
+
315
+ # Implement the required interface for Rails::Generators::Migration.
316
+ def self.next_migration_number(dirname) #:nodoc:
317
+ if ActiveRecord::Base.timestamped_migrations
318
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
319
+ else
320
+ "%.3d" % (current_migration_number(dirname) + 1)
321
+ end
322
+ end
126
323
 
127
324
  end
128
325
 
@@ -24,6 +24,7 @@ module Mdwa
24
24
  class_option :skip_questions, :desc => 'Answer no for all questions by default.', :type => :boolean, :default => false
25
25
  class_option :skip_interface, :desc => 'Cretes only models, migrations and associations.', :type => :boolean, :default => false
26
26
  class_option :only_interface, :desc => 'Skips models, associations and migrations.', :type => :boolean, :default => false
27
+ class_option :only_diff_migration, :desc => 'Generates only the migration for fields addition.', :type => :boolean, :default => false
27
28
 
28
29
  def initialize(*args, &block)
29
30
 
@@ -54,22 +55,30 @@ module Mdwa
54
55
  @model.add_attribute MDWA::Generators::ModelAttribute.new( attribute ) unless User.accessible_attributes.to_a.include?( attribute.split(':').first )
55
56
  end
56
57
 
57
- generate "mdwa:scaffold #{scaffold_name} name:string email:string password:password password_confirmation:password #{@model.attributes.collect{|a| a.raw}.join(' ')} #{'--force' if options.force} #{'--ajax' if options.ajax} #{"model=#{options.model}" if options.model} #{'--skip_interface' if options.skip_interface} #{'--only_interface' if options.only_interface} #{'--skip_rake_migrate' if options.skip_rake_migrate} #{'--skip_timestamp' if options.skip_timestamp} #{'--skip_questions' if options.skip_questions} --skip-migrations"
58
+ unless options.only_diff_migration
59
+ generate "mdwa:scaffold #{scaffold_name} name:string email:string password:password password_confirmation:password #{@model.attributes.collect{|a| a.raw}.join(' ')} #{'--force' if options.force} #{'--ajax' if options.ajax} #{"model=#{options.model}" if options.model} #{'--skip_interface' if options.skip_interface} #{'--only_interface' if options.only_interface} #{'--skip_rake_migrate' if options.skip_rake_migrate} #{'--skip_timestamp' if options.skip_timestamp} #{'--skip_questions' if options.skip_questions} --skip-migrations"
60
+ end
58
61
 
59
62
  end
60
63
 
61
64
  def controller_and_view
62
- unless options.skip_interface
63
- # controllers
64
- @inherit_controller = 'A::BackendController' if @model.space == 'a'
65
- template "controllers/#{'ajax_' if options.ajax}controller.rb", "app/controllers/#{@model.space}/#{@model.plural_name}_controller.rb"
66
-
67
- # views - update only
68
- template 'views/update.js.erb', "app/views/#{@model.space}/#{@model.plural_name}/update.js.erb"
69
- end
65
+
66
+ return nil if options.only_diff_migration
67
+ return nil if options.skip_interface
68
+
69
+ # controllers
70
+ @inherit_controller = 'A::BackendController' if @model.space == 'a'
71
+ template "controllers/#{'ajax_' if options.ajax}controller.rb", "app/controllers/#{@model.space}/#{@model.plural_name}_controller.rb"
72
+
73
+ # views - update only
74
+ template 'views/update.js.erb', "app/views/#{@model.space}/#{@model.plural_name}/update.js.erb"
75
+
70
76
  end
71
77
 
72
78
  def model_override
79
+
80
+ return nil if options.only_diff_migration
81
+
73
82
  # locate the mdwa user to discover the roles
74
83
  require_all "#{MDWA::DSL::USERS_PATH}#{@model.singular_name}.rb"
75
84
  @mdwa_user = MDWA::DSL.user(@model.name)
@@ -78,10 +87,11 @@ module Mdwa
78
87
  else
79
88
  @roles = @mdwa_user.user_roles
80
89
  end
81
-
90
+
82
91
  # model override
83
- gsub_file "app/models/#{@model.space}/#{@model.singular_name}.rb", 'ActiveRecord::Base', 'User'
84
- inject_into_class "app/models/#{@model.space}/#{@model.singular_name}.rb", @model.model_class do
92
+ model_path = (@model.specific?) ? "app/models/#{@model.specific_model.space}/#{@model.specific_model.singular_name}.rb" : "app/models/#{@model.space}/#{@model.singular_name}.rb"
93
+ gsub_file model_path, 'ActiveRecord::Base', 'User'
94
+ inject_into_class model_path, @model.model_class do
85
95
  inj = []
86
96
  @roles.each do |role|
87
97
  inj << "\n\n\tafter_create :create_#{role.underscore}_permission\n"
@@ -93,6 +103,7 @@ module Mdwa
93
103
  end
94
104
  inj.join("\n")
95
105
  end
106
+
96
107
  end
97
108
 
98
109
  def migration_override
@@ -100,7 +111,14 @@ module Mdwa
100
111
  # override model attributes to not allow field duplicity (causing errors)
101
112
  @model.attributes = []
102
113
  attributes.each do |attribute|
103
- @model.add_attribute MDWA::Generators::ModelAttribute.new( attribute ) unless @predefined_fields.include?( attribute.split(':').first )
114
+ attr = MDWA::Generators::ModelAttribute.new( attribute )
115
+
116
+ # add to model attributes
117
+ # if it's not predefined in devise
118
+ # if it's a belongs_to or nested_one association
119
+ if (!attr.references? and !@predefined_fields.include?( attribute.split(':').first )) or attr.belongs_to? or attr.nested_one?
120
+ @model.add_attribute attr
121
+ end
104
122
  end
105
123
  migration_template 'migrate.rb', "db/migrate/add_#{@model.attributes.collect{|a| a.name}.join('_')}_to_users" unless @model.attributes.empty?
106
124
 
@@ -109,7 +127,7 @@ module Mdwa
109
127
  "\n\nPermission.create( :name => '#{@model.singular_name}' ) if Permission.find_by_name('#{@model.singular_name}').nil?"
110
128
  end
111
129
  # run rake db:seeds
112
- if yes?('Run rake db:seed to create permission type?')
130
+ if !options.skip_questions and yes?('Run rake db:seed to create permission type?')
113
131
  rake 'db:migrate'
114
132
  rake 'db:seed'
115
133
  end
@@ -51,7 +51,16 @@ module MDWA
51
51
  end
52
52
 
53
53
  def generate_route
54
- "#{self.method.to_s} '#{self.entity.name.underscore.pluralize}#{'/:id' if member?}/#{self.name.to_s}' => :#{self.name.to_sym}"
54
+ str = []
55
+ str << "#{self.method.to_s} "
56
+ str << "'#{self.entity.name.underscore.pluralize}"
57
+ str << '/:id' if member?
58
+ str << "/#{self.name.to_s}' "
59
+ str << "=> '#{self.entity.name.underscore.pluralize}##{self.name.to_sym}'"
60
+ str << ", :as => '"
61
+ str << "#{self.name.to_s}_#{member? ? self.entity.name.underscore.singularize : self.entity.name.underscore.pluralize}" # action_entity(s)
62
+ str << "'"
63
+ str.join
55
64
  end
56
65
 
57
66
  def generate_controller