modalfields 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.0
1
+ 1.4.0
@@ -321,8 +321,115 @@ module ModalFields
321
321
  true
322
322
  end
323
323
 
324
+ def report(options={})
325
+ dbmodels(dbmodel_options).each do |model, file|
326
+ if options[:tables]
327
+ yield :table, model.table_name, nil, {:model=>model}
328
+ end
329
+
330
+ submodels = model.send(:subclasses)
331
+ existing_fields, association_fields, pk_fields = model_existing_fields(model, submodels)
332
+ unless file.nil?
333
+ pre, start_fields, fields, end_fields, post = split_model_file(file)
334
+ else
335
+ end
336
+
337
+ pks = pk_fields.map{|pk_field_name| existing_fields.find{|f| f.name==pk_field_name}}
338
+ existing_fields.reject!{|f| f.name.in? pk_fields}
339
+ if options[:primary_keys]
340
+ pks.each do |pk_field|
341
+ yield :primary_key, model.table_name, pk_field.name, field_data(pk_field)
342
+ end
343
+ end
344
+
345
+ assoc_cols = []
346
+ association_fields.each do |assoc, cols|
347
+ if options[:associations]
348
+ if assoc.options[:polymorphic]
349
+ foreign_table = :polymorphic
350
+ else
351
+ foreign_table = assoc.klass.table_name
352
+ end
353
+ yield :association, model.table_name, assoc.name, {:foreign_table=>foreign_table}
354
+ end
355
+ Array(cols).each do |col|
356
+ col = existing_fields.find{|f| f.name.to_s==col.to_s}
357
+ assoc_cols << col
358
+ if options[:foreign_keys]
359
+ yield :foreign_key, model.table_name, col.name, field_data(col, :assoc=>assoc)
360
+ end
361
+ end
362
+ end
363
+ existing_fields -= assoc_cols
364
+
365
+ fields = Array(fields).reject{|line, name, comment| name.blank?}
366
+ if model.respond_to?(:fields_info)
367
+ field_order = model.fields_info.map(&:name).map(&:to_s) & existing_fields.map(&:name)
368
+ else
369
+ field_order = []
370
+ end
371
+ if options[:undeclared_fields]
372
+ field_order += existing_fields.map(&:name).reject{|name| field_order.include?(name.to_s)}
373
+ end
374
+ field_comments = Hash[fields.map{|line, name, comment| [name,comment]}]
375
+ field_extras = Hash[ model.fields_info.map{|fi| [fi.name.to_s,fi.attributes]}]
376
+ field_order.each do |field_name|
377
+ field_info = existing_fields.find{|f| f.name.to_s==field_name}
378
+ field_comment = field_comments[field_name]
379
+ field_extra = field_extras[field_name]
380
+ if field_info.blank?
381
+ raise " MISSING FIELD: #{field_name} (#{model})"
382
+ else
383
+ yield :field, model.table_name, field_info.name, field_data(field_info, :comments=>field_comment, :extra=>field_extra)
384
+ end
385
+ end
386
+
387
+ end
388
+ end
389
+
324
390
  private
325
391
 
392
+ def field_data(field_info, options={})
393
+ comments = options[:comments]
394
+ extra = options[:extra]
395
+ assoc = options[:assoc]
396
+ attrs = [:type, :sql_type, :default, :null]
397
+ data = {}
398
+ if comments.present?
399
+ comments = comments.strip
400
+ comments = comments[1..-1] if comments.starts_with?('#')
401
+ comments = comments.strip
402
+ end
403
+ data[:comments] = comments if comments.present?
404
+ if assoc.present?
405
+ data[:foreign_name] = assoc.name
406
+ if assoc.options[:polymorphic]
407
+ data[:foreign_table] = :polymorphic
408
+ else
409
+ data[:foreign_table] = assoc.klass.table_name
410
+ end
411
+ end
412
+ # case field_info.type
413
+ # when :string, :text, :binary, :integer
414
+ # attrs << :limit
415
+ # when :decimal
416
+ # attrs << :scale << :precision
417
+ # when :geometry
418
+ # attrs << :srid
419
+ # end
420
+ attrs += ModalFields.definitions[field_info.type].keys
421
+ attrs = attrs.uniq
422
+ if extra.present?
423
+ extra = extra.except(*attrs)
424
+ end
425
+ attrs.each do |attr|
426
+ v = field_info.send(attr)
427
+ data[attr] = v if v.present?
428
+ end
429
+ data[:extra] = extra if extra.present?
430
+ data
431
+ end
432
+
326
433
  # Return the database models
327
434
  # Options:
328
435
  # :all_models # Return also models in plugins, not only in the app (app/models)
@@ -336,16 +443,16 @@ module ModalFields
336
443
 
337
444
  models_dir = 'app/models'
338
445
  if Rails.respond_to?(:application)
339
- models_dir = Rails.application.paths[models_dir]
446
+ model_dirs = Rails.application.paths[models_dir]
447
+ else
448
+ model_dirs = [models_dir]
340
449
  end
341
450
  models_dir = Rails.root.join(models_dir)
451
+ model_dirs = model_dirs.map{|d| Rails.root.join(d)}
342
452
 
343
453
  if options[:all_models]
344
454
  # Include also models from plugins
345
455
  model_dirs = $:.grep(/\/models\/?\Z/)
346
- else
347
- # Only main application models
348
- model_dirs = [models_dir]
349
456
  end
350
457
 
351
458
  models = []
@@ -427,24 +534,10 @@ module ModalFields
427
534
  # declarations.
428
535
  # * deleted_fields are fields declared in the fields block but not present in the current schema.
429
536
  def diff(model)
430
- # model.columns will fail if the table does not exist
431
- existing_fields = model.columns rescue []
432
- deleted_model = existing_fields.empty?
433
537
  submodels = model.send(:subclasses)
434
- assocs = model.reflect_on_all_associations(:belongs_to) +
435
- submodels.map{|sc| sc.reflect_on_all_associations(:belongs_to)}.flatten
436
- association_fields = assocs.map{ |r|
437
- # up to ActiveRecord 3.1 we had primary_key_name in AssociationReflection; now it's foreign_key
438
- cols = [r.respond_to?(:primary_key_name) ? r.primary_key_name : r.foreign_key]
439
- if r.options[:polymorphic]
440
- t = r.options[:foreign_type]
441
- t ||= r.foreign_type if r.respond_to?(:foreign_type)
442
- t ||= cols.first.sub(/_id\Z/,'_type')
443
- cols << t
444
- end
445
- cols
446
- }.flatten.map(&:to_s)
447
- pk_fields = Array(model.primary_key).map(&:to_s)
538
+ existing_fields, association_fields, pk_fields = model_existing_fields(model, submodels)
539
+ association_fields = association_fields.map{|assoc_name, cols| cols}.flatten.map(&:to_s)
540
+ deleted_model = existing_fields.empty?
448
541
  case show_primary_keys
449
542
  when true
450
543
  pk_fields = []
@@ -617,6 +710,30 @@ module ModalFields
617
710
  fields_info.kind_of?(Array) ? fields_info : nil
618
711
  end
619
712
 
713
+ # Returns three arrays:
714
+ # * array of existing fields (column info objects)
715
+ # * array of association fields: each element is the association information followed by the foreign key fields
716
+ # * array of primary key field names
717
+ def model_existing_fields(model, submodels=[])
718
+ # model.columns will fail if the table does not exist
719
+ existing_fields = model.columns rescue []
720
+ assocs = model.reflect_on_all_associations(:belongs_to) +
721
+ submodels.map{|sc| sc.reflect_on_all_associations(:belongs_to)}.flatten
722
+ association_fields = assocs.map{ |r|
723
+ # up to ActiveRecord 3.1 we had primary_key_name in AssociationReflection; now it's foreign_key
724
+ cols = [r.respond_to?(:primary_key_name) ? r.primary_key_name : r.foreign_key]
725
+ if r.options[:polymorphic]
726
+ t = r.options[:foreign_type]
727
+ t ||= r.foreign_type if r.respond_to?(:foreign_type)
728
+ t ||= cols.first.sub(/_id\Z/,'_type')
729
+ cols << t
730
+ end
731
+ [r, cols]
732
+ }
733
+ pk_fields = Array(model.primary_key).map(&:to_s)
734
+ [existing_fields, association_fields, pk_fields]
735
+ end
736
+
620
737
  end
621
738
 
622
739
 
@@ -0,0 +1,36 @@
1
+ namespace :fields do
2
+
3
+ require 'csv'
4
+
5
+ desc "Dump fields information in CSV"
6
+ task :csv=>:environment do
7
+ fn = Rails.root.join('tmp','fields.csv')
8
+ if CSV.constants.map(&:to_sym).include?(:VERSION)
9
+ options = [{
10
+ :headers=>true,
11
+ :col_sep=>';'
12
+ }]
13
+ else
14
+ options = [';']
15
+ end
16
+ CSV.open(fn, 'w', *options) do |csv|
17
+ csv << %w{table column pk assoc foreign sql_type type attributes extra comments}
18
+ ModalFields.report(
19
+ :primary_keys=>true, :foreing_keys=>true,
20
+ :undeclared_fields=>true) do |kind, table, name, data|
21
+ row_data = [table, name, kind==:primary_key]
22
+ if kind==:foreign_key
23
+ row_data << data[:foreign_name] << data[:foreign_table].to_s
24
+ else
25
+ row_data << '' << ''
26
+ end
27
+ attrs = data.except(:sql_type, :type, :extra, :comments).to_json
28
+ extra = data[:extra]
29
+ row_data << data[:sql_type] << data[:type] << attrs << data[:extra] << data[:comments]
30
+ csv << row_data
31
+ end
32
+ end
33
+ puts "Data written to #{fn}"
34
+ end
35
+
36
+ end
@@ -0,0 +1,24 @@
1
+ namespace :fields do
2
+
3
+ desc "Report the current schema"
4
+ task :report=>:environment do
5
+ ModalFields.report(
6
+ :tables=>true, :primary_keys=>true, :foreign_keys=>true, :associations=>true,
7
+ :undeclared_fields=>true) do |kind, table, name, data|
8
+ case kind
9
+ when :table
10
+ puts "="*50
11
+ puts table
12
+ when :association
13
+ puts " Foreign keys for #{name} (table: #{data[:foreign_table]})"
14
+ when :primary_key
15
+ puts " Primary key: #{name} #{data[:sql_type]}"
16
+ when :foreign_key
17
+ puts " #{name} #{data[:sql_type]}"
18
+ else
19
+ puts " #{name} #{data[:sql_type]}"
20
+ end
21
+ end
22
+ end
23
+
24
+ end
data/modalfields.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "modalfields"
8
- s.version = "1.3.0"
8
+ s.version = "1.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Javier Goizueta"]
12
- s.date = "2012-09-06"
12
+ s.date = "2012-09-17"
13
13
  s.description = "ModelFields is a Rails plugin that adds fields declarations to your models."
14
14
  s.email = "jgoizueta@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -31,8 +31,10 @@ Gem::Specification.new do |s|
31
31
  "lib/modalfields/standardfields.rb",
32
32
  "lib/modalfields/tasks.rb",
33
33
  "lib/tasks/check.rake",
34
+ "lib/tasks/csv.rake",
34
35
  "lib/tasks/migrate.rake",
35
36
  "lib/tasks/migration.rake",
37
+ "lib/tasks/report.rake",
36
38
  "lib/tasks/update.rake",
37
39
  "modalfields.gemspec",
38
40
  "test/create_database.rb",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: modalfields
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-06 00:00:00.000000000 Z
12
+ date: 2012-09-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: modalsettings
@@ -193,8 +193,10 @@ files:
193
193
  - lib/modalfields/standardfields.rb
194
194
  - lib/modalfields/tasks.rb
195
195
  - lib/tasks/check.rake
196
+ - lib/tasks/csv.rake
196
197
  - lib/tasks/migrate.rake
197
198
  - lib/tasks/migration.rake
199
+ - lib/tasks/report.rake
198
200
  - lib/tasks/update.rake
199
201
  - modalfields.gemspec
200
202
  - test/create_database.rb
@@ -230,7 +232,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
230
232
  version: '0'
231
233
  segments:
232
234
  - 0
233
- hash: -375049972268577712
235
+ hash: 1905351546743717120
234
236
  required_rubygems_version: !ruby/object:Gem::Requirement
235
237
  none: false
236
238
  requirements: