yaddl 0.0.1

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 (41) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +32 -0
  4. data/lib/tasks/yaddl_tasks.rake +22 -0
  5. data/lib/yaddl.rb +810 -0
  6. data/lib/yaddl/version.rb +3 -0
  7. data/test/dummy/README.rdoc +28 -0
  8. data/test/dummy/Rakefile +6 -0
  9. data/test/dummy/app/assets/javascripts/application.js +13 -0
  10. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  11. data/test/dummy/app/controllers/application_controller.rb +5 -0
  12. data/test/dummy/app/helpers/application_helper.rb +2 -0
  13. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  14. data/test/dummy/bin/bundle +3 -0
  15. data/test/dummy/bin/rails +4 -0
  16. data/test/dummy/bin/rake +4 -0
  17. data/test/dummy/config.ru +4 -0
  18. data/test/dummy/config/application.rb +23 -0
  19. data/test/dummy/config/boot.rb +5 -0
  20. data/test/dummy/config/database.yml +25 -0
  21. data/test/dummy/config/environment.rb +5 -0
  22. data/test/dummy/config/environments/development.rb +29 -0
  23. data/test/dummy/config/environments/production.rb +80 -0
  24. data/test/dummy/config/environments/test.rb +36 -0
  25. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  26. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  27. data/test/dummy/config/initializers/inflections.rb +16 -0
  28. data/test/dummy/config/initializers/mime_types.rb +5 -0
  29. data/test/dummy/config/initializers/secret_token.rb +12 -0
  30. data/test/dummy/config/initializers/session_store.rb +3 -0
  31. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  32. data/test/dummy/config/locales/en.yml +23 -0
  33. data/test/dummy/config/routes.rb +56 -0
  34. data/test/dummy/db/test.sqlite3 +0 -0
  35. data/test/dummy/public/404.html +58 -0
  36. data/test/dummy/public/422.html +58 -0
  37. data/test/dummy/public/500.html +57 -0
  38. data/test/dummy/public/favicon.ico +0 -0
  39. data/test/test_helper.rb +19 -0
  40. data/test/yaddl_test.rb +19 -0
  41. metadata +153 -0
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Brant Wedel
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.
@@ -0,0 +1,3 @@
1
+ = Yaddl
2
+
3
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Yaddl'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rake/testtask'
23
+
24
+ Rake::TestTask.new(:test) do |t|
25
+ t.libs << 'lib'
26
+ t.libs << 'test'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
30
+
31
+
32
+ task default: :test
@@ -0,0 +1,22 @@
1
+ namespace :yaddl do
2
+ desc "Print generated yaml ddl to console"
3
+ task :review do
4
+ y = Yaddl::Yaddl::load("#{Rails.root}/db/*.yaddl")
5
+ y.review()
6
+ end
7
+ desc "Scaffold controllers views and models, skips migrations"
8
+ task :scaffold do
9
+ y = Yaddl::Yaddl::load("#{Rails.root}/db/*.yaddl")
10
+ y.generate("--force --no-assets --skip-migration --helpers=false")
11
+ end
12
+ desc "Regenerate models, skips migrations"
13
+ task :models do
14
+ y = Yaddl::Yaddl::load("#{Rails.root}/db/*.yaddl")
15
+ y.generate("--no-scaffolds")
16
+ end
17
+ desc "Generate migrations, models, controllers and views"
18
+ task :generate do
19
+ y = Yaddl::Yaddl::load("#{Rails.root}/db/*.yaddl")
20
+ y.generate("--force --no-assets --helpers=false")
21
+ end
22
+ end
@@ -0,0 +1,810 @@
1
+ class Yaddl::Yaddl
2
+
3
+ attr_accessor :markup
4
+ attr_accessor :models
5
+ attr_accessor :quiet
6
+
7
+ def self.load(filename)
8
+ y = Yaddl.new
9
+ if filename.include? "*"
10
+ y.markup = ""
11
+ Dir.glob(filename).each do |fn|
12
+ y.markup += File.read(fn) + "\r\n"
13
+ end
14
+ else
15
+ y.markup = File.read(filename)
16
+ end
17
+ y.models = {}
18
+ y
19
+ end
20
+
21
+ def parse_attribute(attribute)
22
+ at = attribute.split(/\:\*?/)
23
+ name = at[0]
24
+ type = "string"
25
+ if at.count > 1
26
+ type = at[1]
27
+ else
28
+ type = "integer" if name =~ /_id$|^id$|_nr$|^nr$|^number$|_number$/
29
+ type = "datetime" if name =~ /_at$|^date$|_date$|_on$|_time$/
30
+ end
31
+ h = { 'name' => at[0], 'type' => type }
32
+ h['default_type'] = at.count == 1
33
+ h
34
+ end
35
+
36
+ def review
37
+ parse
38
+ puts("","--- DATA #{models.to_yaml}","") unless @quiet
39
+ end
40
+
41
+ def generate(options = "")
42
+ @quiet = options.include?("--quiet")
43
+ scaffolds(options)
44
+ end
45
+
46
+ def indent(string, count, char = ' ')
47
+ string.gsub(/([^\n]*)(\n|$)/) do |match|
48
+ last_iteration = ($1 == "" && $2 == "")
49
+ line = ""
50
+ line << (char * count) unless last_iteration || $1 == ""
51
+ line << $1
52
+ line << $2
53
+ line
54
+ end
55
+ end
56
+
57
+ def scaffolds(options = "")
58
+ parse
59
+
60
+ puts("","--- SCAFFOLDS ---","") unless @quiet
61
+
62
+ models.reject{ |k,v| k[0] == "@"}.each do |name,model|
63
+ model['has_one'] ||= {}
64
+ model['has_many'] ||= {}
65
+ model['belongs_to'] ||= {}
66
+ model['attributes'] ||= {}
67
+ model['methods'] ||= {}
68
+ model['code'] ||= {}
69
+ model['code']['top'] ||= []
70
+ model['code']['before'] ||= []
71
+ model['code']['after'] ||= []
72
+ model['code']['controller'] ||= []
73
+
74
+ sc = "rails g scaffold #{name} " + model['attributes'].map{ |k,v| k + ':' + v['type'].sub(/yaml|hash|object|cache/i,"text") }.join(' ') + " " + model['belongs_to'].map{ |k,v| k + ':references' + (v['polymorphic'] ? "{polymorphic}" : "") }.join(' ')
75
+ puts("model: #{sc}") unless @quiet
76
+ `#{sc} #{options}`
77
+
78
+ File.delete("#{Rails.root}/app/views/#{name.underscore.pluralize}/index.json.jbuilder")
79
+ sc = "rails g scaffold #{name} " + model['methods'].reject{ | k, v| !v['primary_ref'] || v['hidden'] }.map{ |k,v| k + ':' + v['type'].to_s.sub(/yaml|hash|object|cache/i,"text").sub(/^$/,"string") }.join(' ') + " " + model['attributes'].reject{ | k, v| v['hidden'] }.map{ |k,v| k + ':' + v['type'].sub(/yaml|hash|object|cache/i,"text") }.join(' ') + " " + model['belongs_to'].reject{ | k, v| v['hidden'] }.map{ |k,v| k + ':references' + (v['polymorphic'] ? "{polymorphic}" : "") }.join(' ')
80
+ puts("index: #{sc}") unless @quiet
81
+ `#{sc} #{options.gsub("--force","")} --skip --no-migrations`
82
+
83
+ File.delete("#{Rails.root}/app/views/#{name.underscore.pluralize}/show.json.jbuilder")
84
+ File.delete("#{Rails.root}/app/views/#{name.underscore.pluralize}/show.html.erb")
85
+ sc = "rails g scaffold #{name} " + model['methods'].reject{ | k, v| k == "to_s" || v['hidden'] }.map{ |k,v| k + ':' + v['type'].to_s.sub(/yaml|hash|object|cache/i,"text").sub(/^$/,"string") }.join(' ') + " " + model['attributes'].reject{ | k, v| v['hidden'] }.map{ |k,v| k + ':' + v['type'].sub(/yaml|hash|object|cache/i,"text") }.join(' ') + " " + model['belongs_to'].reject{ | k, v| v['hidden'] }.map{ |k,v| k + ':references' + (v['polymorphic'] ? "{polymorphic}" : "") }.join(' ')
86
+ puts("show: #{sc}") unless @quiet
87
+ `#{sc} #{options.gsub("--force","")} --skip --no-migrations`
88
+
89
+ File.delete("#{Rails.root}/app/views/#{name.underscore.pluralize}/_form.html.erb")
90
+ sc = "rails g scaffold #{name} " + model['attributes'].reject{ | k, v| v['hidden'] }.map{ |k,v| k + ':' + v['type'].sub(/yaml|hash|object|cache/i,"text") }.join(' ') + " " + model['belongs_to'].reject{ | k, v| v['hidden'] }.map{ |k,v| k + ':references' + (v['polymorphic'] ? "{polymorphic}" : "") }.join(' ')
91
+ puts("form: #{sc}") unless @quiet
92
+ `#{sc} #{options.gsub("--force","")} --skip --no-migrations`
93
+ end if !options.include?("--no-scaffold")
94
+
95
+
96
+ models.reject{ |k,v| k[0] == "@"}.each do |name,model|
97
+ model['has_one'] ||= {}
98
+ model['has_many'] ||= {}
99
+ model['belongs_to'] ||= {}
100
+ model['attributes'] ||= {}
101
+ model['methods'] ||= {}
102
+ model['code'] ||= {}
103
+ model['code']['top'] ||= []
104
+ model['code']['before'] ||= []
105
+ model['code']['after'] ||= []
106
+ model['code']['controller'] ||= []
107
+
108
+ file = "class #{name} < ActiveRecord::Base"
109
+ model['code']['top'].each do |code|
110
+ file += "\n #{code.each_line{|l| " " + l}}"
111
+ end
112
+ file += "\n" if model['code']['top'].length > 0
113
+
114
+ model['belongs_to'].each do |k,assoc|
115
+ file += "\n belongs_to :#{k}"
116
+ file += ", #{assoc.reject{|k,v| k == "hidden" || k == "class_names" || (k == "class_name" && assoc['polymorphic'])}.map{|k,v| v == true || v == false || v.is_a?(Array) || v.downcase == v ? "#{k}: #{":" unless v == true || v == false || v.is_a?(Array) }#{v}" : "#{k}: \"#{v}\"" }.join(', ')}" if assoc.reject{|k,v| k == "hidden" || k == "class_names" || (k == "class_name" && assoc['polymorphic'])}.count > 0
117
+ end
118
+
119
+ model['has_one'].each do |k,assoc|
120
+ file += "\n has_one :#{k.underscore}"
121
+ file += ", #{assoc.reject{|k,v| k == "hidden" || k == "class_names"}.map{|k,v| v == true || v == false || v.is_a?(Array) || v.downcase == v ? "#{k}: #{":" unless v == true || v == false || v.is_a?(Array) }#{v}" : "#{k}: \"#{v}\"" }.join(', ')}" if assoc.reject{|k,v| k == "hidden" || k == "class_names"}.count > 0
122
+ end
123
+
124
+ model['has_many'].reject{|k,v| v['polymorphic']}.each do |k,assoc|
125
+ file += "\n has_many :#{k.pluralize.underscore}"
126
+ file += ", #{assoc.reject{|k,v| k == "hidden" || k == "polymorphic" || k == "class_names"}.map{|k,v| v == true || v == false || v.is_a?(Array) || v.downcase == v ? "#{k}: #{":" unless v == true || v == false || v.is_a?(Array) }#{v}" : "#{k}: \"#{v}\"" }.join(', ')}" if assoc.reject{|k,v| k == "hidden" || k == "polymorphic" || k == "class_names"}.count > 0
127
+ end
128
+ model['has_many'].select{|k,v| v['polymorphic']}.each do |k,assoc|
129
+ file += "\n has_many :#{k.pluralize.underscore}"
130
+ file += ", #{(assoc.reject{|k,v| k == "hidden" || k == "polymorphic" || k == "class_names"}.map{|k,v| v == true || v == false || v.is_a?(Array) || v.downcase == v ? "#{k}: #{":" unless v == true || v == false || v.is_a?(Array) }#{v}" : "#{k}: \"#{v}\"" }+["as: :#{assoc['foreign_key'].gsub(/_id$/,"")}"]).join(', ')}" if assoc.reject{|k,v| k == "hidden" || k == "polymorphic" || k == "class_names"}.count > 0
131
+ end
132
+
133
+ file += "\n" # if model['belongs_to'].count + model['attributes'].count > 0
134
+ #file += "\n attr_accessible :created_at, :updated_at"
135
+ file += "\n attr_accessible #{model['belongs_to'].map{ |k,v| ":#{k}_id" }.join(', ')}" if model['belongs_to'].count > 0
136
+ file += "\n attr_accessible #{model['belongs_to'].reject{ |k,v| !v['polymorphic'] }.map{ |k,v| ":#{k}_type" }.join(', ')}" if model['belongs_to'].reject{ |k,v| !v['polymorphic'] }.count > 0
137
+ file += "\n attr_accessible #{model['attributes'].map{ |k,v| ":#{k}" }.join(', ')}" if model['attributes'].count > 0
138
+
139
+ file += "\n" if model['has_many'].reject{|k,v| v['dependent'] != 'destroy' }.count + model['has_one'].reject{|k,v| v['dependent'] != 'destroy' }.count > 0
140
+ file += "\n accepts_nested_attributes_for #{model['has_one'].reject{|k,v| v['dependent'] != 'destroy' }.map{ |k,v| ":#{k}" }.join(', ')}" if model['has_one'].reject{|k,v| v['dependent'] != 'destroy' }.count > 0
141
+ file += "\n accepts_nested_attributes_for #{model['has_many'].reject{|k,v| v['dependent'] != 'destroy' }.map{ |k,v| ":#{k}" }.join(', ')}" if model['has_many'].reject{|k,v| v['dependent'] != 'destroy' }.count > 0
142
+
143
+ file += "\n" if model['code']['before'].length > 0
144
+ model['code']['before'].each do |code|
145
+ file += "\n#{indent(code, 2)}"
146
+ end
147
+
148
+ model['methods'].each do |k,assoc|
149
+ if assoc['getter']
150
+ file += "\n"
151
+ assoc.each do |k,v|
152
+ file += "\n # #{k}: #{v}" if k != 'getter' && k != 'setter' && k != 'takes'
153
+ end
154
+ file += "\n def #{k}"
155
+ file += "\n #{assoc['getter']}"
156
+ file += "\n end"
157
+ end
158
+ if assoc['setter']
159
+ file += "\n"
160
+ assoc.each do |k,v|
161
+ file += "\n # #{k}: #{v}" if k != 'getter' && k != 'setter' && k != 'returns'
162
+ end
163
+ file += "\n def #{k}=(value)"
164
+ file += "\n #{assoc['setter']}"
165
+ file += "\n end"
166
+ end
167
+ end
168
+
169
+ file += "\n" if model['code']['after'].length > 0
170
+ model['code']['after'].each do |code|
171
+ file += "\n#{indent(code, 2)}"
172
+ end
173
+
174
+ file += "\nend\n"
175
+
176
+ puts("app/models/#{name.underscore}.rb") unless @quiet
177
+ File.open("#{Rails.root}/app/models/#{name.underscore}.rb", "w") do |f|
178
+ f.write(file)
179
+ end
180
+
181
+ next if options.include?("--no-scaffold")
182
+
183
+ puts("app/controllers/#{name.underscore.pluralize}_controller.rb") unless @quiet
184
+
185
+
186
+ file = File.read("#{Rails.root}/app/controllers/#{name.underscore.pluralize}_controller.rb")
187
+ file.sub!(" # GET /#{name.underscore.pluralize}
188
+ # GET /#{name.underscore.pluralize}.json
189
+ def index
190
+ @#{name.underscore.pluralize} = #{name}.all
191
+ end", "#{model['code']['controller'].map{|line| " #{line}
192
+ "}.join}#{"
193
+ " if model['code']['controller'].length > 0} # GET /#{name.underscore.pluralize}
194
+ # GET /#{name.underscore.pluralize}.json
195
+ def index
196
+ @#{name.underscore.pluralize} = #{name}.all#{ model['belongs_to'].map do |attr_name, assoc| "
197
+ if params[:#{attr_name.underscore}_id]
198
+ @#{name.underscore.pluralize} = @#{name.underscore.pluralize}.where(#{attr_name.underscore}_id: params[:#{attr_name.underscore}_id])
199
+ end
200
+ " end.join }#{ "
201
+ " if true || model['belongs_to'].count > 0 } end")
202
+
203
+
204
+ file.sub!(" # GET /#{name.underscore}/1
205
+ # GET /#{name.underscore}/1.json
206
+ def show
207
+ end"," # GET /#{name.underscore}/1
208
+ # GET /#{name.underscore}/1.json
209
+ def show
210
+ @#{name.underscore} = #{name}.new#{ model['belongs_to'].map do |attr_name, assoc| "
211
+ if params[:#{attr_name.underscore}_id]
212
+ @#{name.underscore}.#{attr_name.underscore}_id = params[:#{attr_name.underscore}_id]
213
+ end
214
+ " end.join } end")
215
+
216
+
217
+ file.sub!(" # GET /#{name.underscore.pluralize}/new
218
+ def new
219
+ @#{name.underscore} = #{name}.new
220
+ end"," # GET /#{name.underscore.pluralize}/new
221
+ def new
222
+ @#{name.underscore} = #{name}.new#{ model['belongs_to'].map do |attr_name, assoc| "
223
+ if params[:#{attr_name.underscore}_id]
224
+ @#{name.underscore}.#{attr_name.underscore}_id = params[:#{attr_name.underscore}_id]
225
+ end
226
+ " end.join } end")
227
+
228
+
229
+
230
+ File.open("#{Rails.root}/app/controllers/#{name.underscore.pluralize}_controller.rb", "w") do |f|
231
+ f.write(file)
232
+ end
233
+
234
+ puts("app/views/#{name.underscore.pluralize}/index.html.erb") unless @quiet
235
+ File.open("#{Rails.root}/app/views/#{name.underscore.pluralize}/index.html.erb", "w") do |f|
236
+
237
+ names = model['attributes'].reject{ |k,v| v['hidden'] }.merge(model['methods'].reject{ |k,v| v['hidden'] }.merge(model['belongs_to'].reject{ |k,v| v['hidden'] })).reject{ | k, v| !v['primary_ref'] }
238
+ names = model['attributes'].reject{ |k,v| v['hidden'] }.merge(model['belongs_to'].reject{ |k,v| v['hidden'] }) if names.count == 0
239
+
240
+ f.write "<h1>Listing #{name.titleize.pluralize}</h1>
241
+
242
+ <table>
243
+ <thead>
244
+ <tr>
245
+ #{ names.map do |k, v|
246
+ " <th>#{k.titlecase}</th>
247
+ "
248
+ end.join } <th></th>
249
+ <th></th>
250
+ <th></th>
251
+ </tr>
252
+ </thead>
253
+
254
+ <tbody>
255
+ <% @#{name.underscore.pluralize}.each do |#{name.underscore}| %>
256
+ <tr>
257
+ #{ names.map do |k, v|
258
+ " <th><%= #{name.underscore}.#{k.underscore} %></th>
259
+ "
260
+ end.join } <td><%= link_to 'Show', #{name.underscore} %></td>
261
+ <td><%= link_to 'Edit', edit_#{name.underscore}_path(#{name.underscore}) %></td>
262
+ <td><%= link_to 'Destroy', #{name.underscore}, method: :delete, data: { confirm: 'Are you sure?' } %></td>
263
+ </tr>
264
+ <% end %>
265
+ </tbody>
266
+ </table>
267
+
268
+ <br>
269
+
270
+ <%= link_to 'New #{name.titleize}', url_for([:new, #{(model['belongs_to'].map{ |k,v| "@" + k.underscore } + [":#{name.underscore}"] ).join(', ')}]) %>
271
+ "
272
+ end
273
+
274
+
275
+
276
+
277
+
278
+
279
+ puts("app/views/#{name.underscore.pluralize}/show.html.erb") unless @quiet
280
+ File.open("#{Rails.root}/app/views/#{name.underscore.pluralize}/show.html.erb", "w") do |f|
281
+
282
+ names = model['attributes'].reject{ |k,v| v['hidden'] }.merge(model['methods'].reject{ |k,v| v['hidden'] }.reject{ |k,v| v['returns'].to_s.downcase != v['returns'].to_s }).reject{ |name, v| name == "to_s"}
283
+
284
+ f.write "<p id=\"notice\"><%= notice %></p>
285
+
286
+ <h1>#{name.titleize}#{ " <%= @"+name.underscore + " %>" if model['methods'].reject{ |k,v| k != "to_s" }.count > 0 }</h1>
287
+
288
+ #{names.map do |attr_name, v|
289
+ "<p>
290
+ <strong>#{attr_name.titleize}:</strong>
291
+ <%= @#{name.underscore}.#{attr_name.underscore} %>
292
+ </p>
293
+
294
+ " end.join }#{
295
+ model['belongs_to'].merge(model['methods'].reject{ |k,v| v['returns'].to_s.downcase == v['returns'].to_s }).map do |attr_name,v|
296
+ "<p>
297
+ <strong>#{attr_name.titleize}:</strong>
298
+ <%= link_to @#{name.underscore}.#{attr_name.underscore}, @#{name.underscore}.#{attr_name.underscore} %>
299
+ </p>
300
+
301
+ " end.join }<%= link_to 'Edit', edit_#{name.underscore}_path(@#{name.underscore}) %> |
302
+ <%= link_to 'Back', url_for([#{(model['belongs_to'].map{ |k,v| "@" + k.underscore } + [":#{name.underscore.pluralize}"]).join(', ')}]) rescue #{name.underscore.pluralize}_path %>
303
+ #{ model['has_many'].map do |model,v|
304
+ "
305
+ <div class=\"has-many-index\">
306
+ <% notice = nil %>
307
+ <% @#{(v['class_name'] || model).underscore.downcase.pluralize} = @#{name.underscore}.#{model.underscore.pluralize} %>
308
+ <%= render template: \"#{(v['class_name'] || model).underscore.downcase.pluralize}/index\" %>
309
+ </div>" end.join }
310
+ "
311
+ end
312
+
313
+
314
+ puts("app/views/#{name.underscore.pluralize}/_form.html.erb") unless @quiet
315
+ f_content = File.read("#{Rails.root}/app/views/#{name.underscore.pluralize}/_form.html.erb")
316
+ File.open("#{Rails.root}/app/views/#{name.underscore.pluralize}/_form.html.erb", "w") do |f|
317
+
318
+ model['belongs_to'].each do |k,assoc|
319
+ if assoc['polymorphic']
320
+ f_content.gsub!(" <%= f.association :#{k} %>", " <%= f.input :#{k}_type, collection: #{assoc['class_names']} %><%= f.association :#{k}, collection: #{assoc['class_names'].map{ |word| "#{word}.all" }.join(" + ")} %>")
321
+ end
322
+ #file += ", #{assoc.reject{|k,v| k == "hidden" || k == "class_names" || (k == "class_name" && assoc['polymorphic'])}.map{|k,v| v == true || v == false || v.is_a?(Array) || v.downcase == v ? "#{k}: #{":" unless v == true || v == false || v.is_a?(Array) }#{v}" : "#{k}: \"#{v}\"" }.join(', ')}" if assoc.reject{|k,v| k == "hidden" || k == "class_names" || (k == "class_name" && assoc['polymorphic'])}.count > 0
323
+ end
324
+
325
+ f.write f_content
326
+ end
327
+
328
+
329
+ #puts "rails g scaffold #{name} " + model['attributes'].map{ |k,v| k + ':' + v['type'].sub(/yaml|hash|object|cache/i,"text") }.join(' ') + " " + model['has_one'].map{ |k,v| k + ':references' + (v['polymorphic'] ? "{polymorphic}" : "") }.join(' ') + " #{options}"
330
+ end
331
+
332
+ cleanup(ddl: true, mixins: false)
333
+
334
+ File.open("#{Rails.root}/db/schema.yaml", "w") do |f|
335
+ f.write models.to_yaml
336
+ end
337
+
338
+ puts("","--- DATA #{models.to_yaml}","") unless @quiet
339
+ end
340
+
341
+ def parse
342
+ #puts ""
343
+ #puts "--- PARSE ---"
344
+ self.models = {}
345
+ stack = [nil]
346
+ depth = 0
347
+ self.markup.gsub(/.---..*/m,"").lines.each do |line|
348
+ next if (line.strip == "" || line.strip.start_with?("#")) && !@multiline
349
+ parse_line(line, self.models, stack, depth)
350
+ end
351
+
352
+
353
+ lines = []
354
+ models.select{ |k,v| k[0] != "@"}.each do |model,v0|
355
+
356
+ if models["@Default"] != nil && (!models['has_many'] || models['has_many']['@defaults'] != nil)
357
+ name = "@default"
358
+ type = "@Default"
359
+ if name[0] == "@"
360
+ puts("#{model} > #{type}") unless @quiet
361
+ v0['includes'] ||= []
362
+ v0['includes'] << type
363
+ v0['includes'].uniq!
364
+ models[type]['ddl'].select{|v| v.start_with?(type + " > ")}.each do |ddl|
365
+ line = ddl.sub("#{type} > ","")
366
+ line.gsub!("___","")
367
+ puts(" #{line}") unless @quiet
368
+ lines << {'model' => model, 'content' => line}
369
+ end
370
+ end
371
+ end
372
+
373
+ v0['belongs_to'].each do |k,v1|
374
+ v1['class_names'].each do |v|
375
+ if v[0] == "@"
376
+ name = k
377
+ name += "_" unless name.end_with?("_")
378
+ type = v
379
+ if name[0] != "@"
380
+ next if name.include? "___"
381
+ puts("#{model} > #{name}:#{type}") unless @quiet
382
+ v0['includes'] ||= []
383
+ v0['includes'] << "#{name}:#{type}"
384
+ v0['includes'].uniq!
385
+ models[type]['ddl'].select{|v| v.start_with?(type + " > ")}.each do |ddl|
386
+ line = ddl.sub("#{type} > ","")
387
+ #name2 = line.sub(/ *[\+\-\*\=\&]*([@A-Za-z0-9_]+).*/,'\1')
388
+ #data_type = nil
389
+ #data_type = line.sub(/^ *[\+\-\*\=\&]*[@A-Za-z0-9_]+\:?([@A-Za-z0-9_]+).*/,'\1') if line =~ /^ *[\+\-\*\=\&]*[@A-Za-z0-9_]+\:[@A-Za-z0-9_]+.*/
390
+ #flags = line.sub(/\s*([\-\+\*\&\=]+).*/,'\1') if line =~ /\s*([\-\+\*\&\=]+).*/
391
+ line.gsub!("___",name)
392
+ puts(" #{line}") unless @quiet
393
+ lines << {'model' => model, 'content' => line}
394
+ end
395
+ end
396
+ end
397
+ end
398
+ end if v0['belongs_to']
399
+
400
+ v0['has_one'].each do |k,v1|
401
+ v1['class_names'].each do |v|
402
+ if v[0] == "@"
403
+ name = k
404
+ type = v
405
+ if name[0] == "@"
406
+ puts("#{model} > #{type}") unless @quiet
407
+ v0['includes'] ||= []
408
+ v0['includes'] << type
409
+ v0['includes'].uniq!
410
+ models[type]['ddl'].select{|v| v.start_with?(type + " > ")}.each do |ddl|
411
+ line = ddl.sub("#{type} > ","")
412
+ line.gsub!("___","")
413
+ puts(" #{line}") unless @quiet
414
+ lines << {'model' => model, 'content' => line}
415
+ end
416
+ end
417
+ end
418
+ end
419
+ end if v0['has_one']
420
+ end
421
+
422
+ cleanup(ddl: true, mixins: false)
423
+
424
+ lines.each do |line|
425
+ stack = [line['model'],nil,nil,nil,nil]
426
+ depth = 1
427
+ parse_line(line['content'], models, stack, depth)
428
+ end
429
+
430
+ #throw "DDL"
431
+ puts("","--- DDL ---","") unless @quiet
432
+
433
+ models
434
+ end
435
+
436
+ def cleanup(options = {})
437
+
438
+ options[:ddl] ||= false
439
+ options[:mixins] ||= false
440
+
441
+ #models.reject!{ |k,v| k[0] == "@"}
442
+ models.each do |model,v0|
443
+
444
+ v0.delete('ddl') if options[:ddl] == true
445
+
446
+ v0['has_one'].select{true}.each do |k,v1|
447
+ v0['has_one'].delete(k) if k[0] == "@"
448
+ v1['class_names'].select{true}.each do |v|
449
+ if v[0] == "@"
450
+ v0['has_one'].delete(k)
451
+ break
452
+ end
453
+ end
454
+ end if v0['has_one']
455
+ v0.delete('has_one') if v0['has_one'] == {}
456
+
457
+ v0['has_many'].select{true}.each do |k,v1|
458
+ v0['has_many'].delete(k) if k[0] == "@"
459
+ v1['class_names'].select{true}.each do |v|
460
+ if v[0] == "@"
461
+ v0['has_many'].delete(k)
462
+ break
463
+ end
464
+ end
465
+ end if v0['has_many']
466
+ v0.delete('has_many') if v0['has_many'] == {}
467
+
468
+ v0['belongs_to'].select{true}.each do |k,v1|
469
+ v0['belongs_to'].delete(k) if k[0] == "@"
470
+ v1['class_names'].select{true}.each do |v|
471
+ if v[0] == "@"
472
+ v0['belongs_to'].delete(k)
473
+ break
474
+ end
475
+ end
476
+ end if v0['belongs_to']
477
+ v0.delete('belongs_to') if v0['belongs_to'] == {}
478
+
479
+ v0.delete('attributes') if v0['attributes'] == {}
480
+ v0.delete('methods') if v0['methods'] == {}
481
+
482
+ if v0['code']
483
+ v0['code'].select{true}.each do |k,v|
484
+ v0['code'].delete(k) if v0['code'][k] == []
485
+ end
486
+ v0.delete('code') if v0['code'] == {}
487
+ end
488
+
489
+ end
490
+
491
+ end
492
+
493
+
494
+ def parse_line(line, models, stack, depth)
495
+ spaces = line[/\A */].size
496
+
497
+ @multiline ||= false
498
+ unless @multiline
499
+ if line.strip =~ /^(def|module|class|if|unless) / || line.strip =~ / do \|.+\|$/ || line.strip =~ / do$/
500
+ @multiline = true
501
+ @multiline_spaces = spaces
502
+ @multiline_end = /^#{" " * @multiline_spaces}end$/
503
+ @multiline_buffer = line[@multiline_spaces..line.length]
504
+ return
505
+ elsif line.strip =~ /^[a-z_]+ |^acts_as_.*/
506
+ if line.strip =~ /"^include |^require |^extend |^acts_as_[a-z_]+/
507
+ line = "!top{#{line.strip}}"
508
+ else
509
+ line = "!!{#{line.strip}}"
510
+ end
511
+ end
512
+ else
513
+ if line.strip == ""
514
+ @multiline_buffer += "\n"
515
+ else
516
+ @multiline_buffer += line[@multiline_spaces..line.length]
517
+ end
518
+ if line =~ @multiline_end
519
+ line = "!after{" + @multiline_buffer.strip + "}"
520
+ spaces = @multiline_spaces
521
+ @multiline = false
522
+ else
523
+ return
524
+ end
525
+ end
526
+
527
+ line.strip!
528
+
529
+ return if line == ""
530
+
531
+ depth = spaces / 2
532
+ parent = nil
533
+ parent = stack[depth]
534
+ if parent && parent[0] != "@"
535
+ line.gsub!("MMMs",parent.pluralize)
536
+ line.gsub!("MMMS",parent.pluralize)
537
+ line.gsub!("MMM",parent)
538
+ line.gsub!("mmms",parent.underscore.downcase.pluralize)
539
+ line.gsub!("mmm",parent.underscore.downcase)
540
+ end
541
+
542
+ if line[0] == "{"
543
+
544
+ depth = spaces / 2
545
+
546
+ parent = nil
547
+ parent = stack[depth]
548
+
549
+ models[parent] ||= {} if parent
550
+
551
+ models[parent]['ddl'] ||= [] if parent
552
+ models[parent]['ddl'] << (parent ? "#{parent} > " : '') + line if parent
553
+
554
+ models[parent]['code'] ||= {} if parent
555
+ models[parent]['code']['after'] ||= [] if parent
556
+ models[parent]['code']['after'] << line[1..-2] if parent
557
+
558
+ return
559
+ elsif line[0] == "!"
560
+
561
+ depth = spaces / 2
562
+
563
+ parent = nil
564
+ parent = stack[depth]
565
+
566
+ models[parent] ||= {} if parent
567
+
568
+ models[parent]['ddl'] ||= [] if parent
569
+ models[parent]['ddl'] << (parent ? "#{parent} > " : '') + line if parent
570
+
571
+ place = line.sub(/^\!\!?(.*\s*)\{.*/m,'\1').strip
572
+ place = 'before' if place == ""
573
+ _unique = line[1] == "!"
574
+ line.sub!(line.sub(/^(\!\!?.*\s*)\{.*/m,'\1'),'')
575
+ models[parent]['code'] ||= {} if parent
576
+ models[parent]['code'][place] ||= [] if parent
577
+ if line[0] == "{"
578
+ if !_unique || !models[parent]['code'][place].include?(line[1..-2])
579
+ models[parent]['code'][place] << line[1..-2]
580
+ end
581
+ else
582
+ if !_unique || !models[parent]['code'][place].include?(line)
583
+ models[parent]['code'][place] << line
584
+ end
585
+ end
586
+
587
+ return
588
+ end
589
+
590
+ name = line.sub(/ *[\+\-\*\=\&]*([@A-Za-z0-9_]+).*/,'\1')
591
+ data_type = nil
592
+ polymorphic = false
593
+
594
+ data_type = line.sub(/^ *[\+\-\*\=\&]*[@A-Za-z0-9_]+\:?([@A-Za-z0-9_]+).*/,'\1') if line =~ /^ *[\+\-\*\=\&]*[@A-Za-z0-9_]+\:[@A-Za-z0-9_]+.*/
595
+ if line =~ /^ *[\+\-\*\=\&]*[@A-Za-z0-9_]+\:\*[@A-Za-z0-9_]+.*/
596
+ data_type = line.sub(/^ *[\+\-\*\=\&]*[@A-Za-z0-9_]+\:\*?([@A-Za-z0-9_]+).*/,'\1')
597
+ polymorphic = true
598
+ end
599
+
600
+ type = "attribute"
601
+ type = "model" if name[0] =~ /[@A-Z]/
602
+ type = "model" if data_type && data_type[0] =~ /[@A-Z]/
603
+
604
+ if data_type && type == "model"
605
+ model = data_type
606
+ elsif type == "model"
607
+ model = name
608
+ end
609
+ model = name if type == "model" && model == nil
610
+
611
+ attributes = []
612
+ attributes = line.sub(/.*\((.*)\).*/,'\1').split(/\s/) if line =~ /.*\((.*)\).*/
613
+
614
+ data = nil
615
+ data = Regexp.last_match[0][1..-2] if line =~ /[\{].*[\}]/xms
616
+
617
+ flags = nil
618
+ flags = line.sub(/\s*([\-\+\*\&\=]+).*/,'\1') if line =~ /\s*([\-\+\*\&\=]+).*/
619
+
620
+ multiplicity = "has_one"
621
+ multiplicity = "has_many" if flags == "*" || flags == ".*" || flags == "*." || flags == "-*" || flags == "*-"
622
+ multiplicity = "has_and_belongs_to_many" if flags == "**" || flags == "+**" || flags == "**+"
623
+ multiplicity = "belongs_to" if flags == "+" || flags == "-+" || flags == "+-" || flags == ".+" || flags == "+."
624
+ multiplicity = "has_many" if flags == "*+" || flags == "+*" || flags == "++"
625
+
626
+ dependent = "destroy"
627
+ dependent = "nullify" if flags == "*+" || flags == "+*" || flags == "++" || flags == "+"
628
+ dependent = nil if flags == "**+" || flags == "+**"
629
+
630
+ hidden = false
631
+ hidden = true if flags == "-" || flags == "-+" || flags == "+-"
632
+ #read_only = false
633
+ #read_only = true if flags == "." || flags == ".+"
634
+ type = "method" if flags == "="
635
+ type = "property" if flags == "=="
636
+ type = "cached" if flags == "&" && type != "model"
637
+
638
+ depth = spaces / 2
639
+ stack[depth+1] = model if type == "model"
640
+
641
+ parent = nil
642
+ parent = stack[depth]
643
+
644
+ #puts "#{parent}#{flags}#{"." if !flags && parent}#{name}:#{model}#{"(" + attributes.join(' ') + ")" if attributes.count > 0}" if parent || attributes.count > 0
645
+
646
+ models[parent] ||= {} if parent
647
+ models[model] ||= {} if type == "model"
648
+
649
+ models[parent]['ddl'] ||= [] if parent
650
+ models[parent]['ddl'] << (parent ? "#{parent} > " : '') + line if parent
651
+ models[model]['ddl'] ||= [] if model
652
+ models[model]['ddl'] << "~" + (parent ? "#{parent} > " : '') + line if model
653
+
654
+ unless (type == "method" || type == "property" || type == "attribute")
655
+ attributes.each do |attribute|
656
+
657
+ _flags = attribute.sub(/([\-\+\*\&\=]+).*/,'\1') if attribute =~ /([\-\+\*\&\=]+).*/
658
+ _mode = 'attributes'
659
+ _mode = 'methods' if _flags == "="
660
+ _hidden = false
661
+ _hidden = true if _flags == "-"
662
+
663
+ at = parse_attribute(attribute.sub(/^[\-\=]+/,""))
664
+ models[model][_mode] ||= {}
665
+ models[model][_mode][at['name']] ||= {}
666
+ if !models[model][_mode][at['name']]['type'] || !at['default_type']
667
+ models[model][_mode][at['name']]['type'] = at['type']
668
+ end
669
+ models[model][_mode][at['name']]['hidden'] = true if _hidden
670
+ models[model][_mode][at['name']]['primary_ref'] ||= []
671
+ models[model][_mode][at['name']]['primary_ref'] << parent
672
+ end
673
+ end
674
+
675
+ if parent && (type == "attribute" || type == "cached")
676
+ at = parse_attribute("#{name}#{":" + data_type if data_type}")
677
+ models[parent]['attributes'] ||= {}
678
+ models[parent]['attributes'][at['name']] = {}
679
+ models[parent]['attributes'][at['name']]['hidden'] = true if hidden
680
+ if !models[parent]['attributes'][at['name']]['type'] || !at['default_type']
681
+ models[parent]['attributes'][at['name']]['type'] = at['type']
682
+ end
683
+ end
684
+
685
+ if parent && (type == "method" || type == "property")
686
+ at = parse_attribute("#{name}#{":" + data_type if data_type}")
687
+ models[parent]['methods'] ||= {}
688
+ models[parent]['methods'][at['name']] ||= {}
689
+ if type == "method"
690
+ models[parent]['methods'][at['name']]['returns'] = at['type']
691
+ unless models[parent]['methods'][at['name']]['setter']
692
+ models[parent]['methods'][at['name']]['getter'] = data.to_s
693
+ else
694
+ models[parent]['methods'][at['name']]['getter'] += "\n " + data if data
695
+ end
696
+ else
697
+ models[parent]['methods'][at['name']]['takes'] = at['type']
698
+ unless models[parent]['methods'][at['name']]['getter']
699
+ models[parent]['methods'][at['name']]['setter'] = data.to_s
700
+ else
701
+ models[parent]['methods'][at['name']]['setter'] += "\n " + data if data
702
+ end
703
+ end
704
+ end
705
+
706
+ if type == "model" && parent
707
+ if multiplicity == "has_many"
708
+ models[parent]['has_many'] ||= {}
709
+ models[parent]['has_many'][name.pluralize.underscore] ||= (model && name != model) ? { 'class_name' => model } : {}
710
+ models[parent]['has_many'][name.pluralize.underscore]['dependent'] = dependent if dependent
711
+ models[parent]['has_many'][name.pluralize.underscore]['foreign_key'] = name.underscore + "_id" if model && name != model
712
+ models[parent]['has_many'][name.pluralize.underscore]['polymorphic'] = true if polymorphic
713
+
714
+ models[parent]['has_many'][name.pluralize.underscore]['class_names'] ||= []
715
+ models[parent]['has_many'][name.pluralize.underscore]['class_names'] << model
716
+ models[parent]['has_many'][name.pluralize.underscore]['class_names'].uniq!
717
+
718
+ models[model]['belongs_to'] ||= {}
719
+ if model && name != model
720
+ models[model]['belongs_to'][name.pluralize.underscore] ||= { 'class_name' => parent }
721
+ models[model]['belongs_to'][name.pluralize.underscore]['hidden'] = true if hidden
722
+ models[model]['belongs_to'][name.pluralize.underscore]['polymorphic'] = true if polymorphic
723
+
724
+ models[model]['belongs_to'][name.pluralize.underscore]['class_names'] ||= []
725
+ models[model]['belongs_to'][name.pluralize.underscore]['class_names'] << parent
726
+ models[model]['belongs_to'][name.pluralize.underscore]['class_names'].uniq!
727
+ else
728
+ models[model]['belongs_to'][parent.underscore] ||= {}
729
+ models[model]['belongs_to'][parent.underscore]['hidden'] = true if hidden
730
+ models[model]['belongs_to'][parent.underscore]['polymorphic'] = true if polymorphic
731
+
732
+ models[model]['belongs_to'][parent.underscore]['class_names'] ||= []
733
+ models[model]['belongs_to'][parent.underscore]['class_names'] << parent
734
+ models[model]['belongs_to'][parent.underscore]['class_names'].uniq!
735
+ end
736
+ end
737
+ if multiplicity == "belongs_to"
738
+ models[parent]['belongs_to'] ||= {}
739
+ models[parent]['belongs_to'][name.underscore] ||= model && name != model ? { 'class_name' => model }: {}
740
+ models[parent]['belongs_to'][name.underscore]['hidden'] = true if hidden
741
+ models[parent]['belongs_to'][name.underscore]['polymorphic'] = true if polymorphic
742
+
743
+ models[parent]['belongs_to'][name.underscore]['class_names'] ||= []
744
+ models[parent]['belongs_to'][name.underscore]['class_names'] << model
745
+ models[parent]['belongs_to'][name.underscore]['class_names'].uniq!
746
+
747
+ models[model]['has_many'] ||= {}
748
+ models[model]['has_many'][parent.pluralize.underscore] ||= (model && name != model) ? { 'class_name' => parent } : {}
749
+ models[model]['has_many'][parent.pluralize.underscore]['dependent'] = dependent if dependent
750
+ models[model]['has_many'][parent.pluralize.underscore]['polymorphic'] = true if polymorphic
751
+
752
+ models[model]['has_many'][parent.pluralize.underscore]['class_names'] ||= []
753
+ models[model]['has_many'][parent.pluralize.underscore]['class_names'] << model
754
+ models[model]['has_many'][parent.pluralize.underscore]['class_names'].uniq!
755
+ end
756
+ if multiplicity == "has_one"
757
+ if model && name != model
758
+ models[parent]['belongs_to'] ||= {}
759
+ models[parent]['belongs_to'][name.underscore] ||= model && name != model ? { 'class_name' => model }: {}
760
+ models[parent]['belongs_to'][name.underscore]['dependent'] = dependent if dependent
761
+ models[parent]['belongs_to'][name.underscore]['hidden'] = true if hidden
762
+ models[parent]['belongs_to'][name.underscore]['polymorphic'] = true if polymorphic
763
+
764
+ models[parent]['belongs_to'][name.underscore]['class_names'] ||= []
765
+ models[parent]['belongs_to'][name.underscore]['class_names'] << model
766
+ models[parent]['belongs_to'][name.underscore]['class_names'].uniq!
767
+
768
+ models[model]['has_many'] ||= {}
769
+ models[model]['has_many'][name.underscore + "_" + parent.underscore.pluralize] ||= model && name != model ? { 'class_name' => parent, 'foreign_key' => name + "_id" }: {}
770
+ models[model]['has_many'][name.underscore + "_" + parent.underscore.pluralize]['dependent'] = dependent if dependent
771
+ models[model]['has_many'][name.underscore + "_" + parent.underscore.pluralize]['polymorphic'] = true if polymorphic
772
+
773
+ models[model]['has_many'][name.underscore + "_" + parent.underscore.pluralize]['class_names'] ||= []
774
+ models[model]['has_many'][name.underscore + "_" + parent.underscore.pluralize]['class_names'] << parent
775
+ models[model]['has_many'][name.underscore + "_" + parent.underscore.pluralize]['class_names'].uniq!
776
+ else
777
+ models[parent]['has_one'] ||= {}
778
+ models[parent]['has_one'][name.underscore] = model && name != model ? { 'class_name' => model }: {}
779
+ models[parent]['has_one'][name.underscore]['dependent'] = dependent if dependent
780
+ models[parent]['has_one'][name.underscore]['hidden'] = true if hidden
781
+ models[parent]['has_one'][name.underscore]['polymorphic'] = true if polymorphic
782
+
783
+ models[parent]['has_one'][name.underscore]['class_names'] ||= []
784
+ models[parent]['has_one'][name.underscore]['class_names'] << model
785
+ models[parent]['has_one'][name.underscore]['class_names'].uniq!
786
+
787
+ models[model]['belongs_to'] ||= {}
788
+ models[model]['belongs_to'][parent.underscore] ||= model && name != model ? { 'class_name' => parent, 'foreign_key' => name + "_id" }: {}
789
+ models[model]['belongs_to'][parent.underscore]['hidden'] = true if hidden
790
+ models[model]['belongs_to'][parent.underscore]['polymorphic'] = true if polymorphic
791
+
792
+ models[model]['belongs_to'][parent.underscore]['class_names'] ||= []
793
+ models[model]['belongs_to'][parent.underscore]['class_names'] << parent
794
+ models[model]['belongs_to'][parent.underscore]['class_names'].uniq!
795
+ end
796
+
797
+ #models[model]['belongs_to'] ||= {}
798
+ #models[model]['belongs_to'][parent.underscore] ||= {}
799
+ #models[model]['has_many'] ||= {}
800
+ #models[model]['has_many'][parent.pluralize.underscore] ||= model && name != model ? { 'foreign_key' => name }: {}
801
+ end
802
+ end
803
+
804
+ end
805
+
806
+
807
+
808
+
809
+
810
+ end