modalfields 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/lib/modalfields/modalfields.rb +138 -21
- data/lib/tasks/csv.rake +36 -0
- data/lib/tasks/report.rake +24 -0
- data/modalfields.gemspec +4 -2
- metadata +5 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
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
|
-
|
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
|
-
|
435
|
-
|
436
|
-
|
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
|
|
data/lib/tasks/csv.rake
ADDED
@@ -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.
|
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-
|
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.
|
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-
|
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:
|
235
|
+
hash: 1905351546743717120
|
234
236
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
235
237
|
none: false
|
236
238
|
requirements:
|