mdd 3.0.6 → 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
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