activefacts-generators 1.8.2 → 1.8.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fae26b2c7cc83608173f074aaed203e14715b5a5
4
- data.tar.gz: c4d0e31dc92866f042a82baebe67c0369414cb2d
3
+ metadata.gz: 18414a4533151ffe192e7ae375366327595faf25
4
+ data.tar.gz: 6d31af89a93cfa0d63edf126cacb3df917770cd3
5
5
  SHA512:
6
- metadata.gz: d2f8719f99dcb8f5b4425d46e558e9862ba0a0dc51c16ab58a67c78ba4faa0add7fc2ced31fc5a58188bc568a7b76fdfecb23892fda04261591a8c8806bc68f4
7
- data.tar.gz: 930d7bc060c4d53c4913dec4510b4609dd1177cc13a005e1e13993527ee083a79e32e3f600b60b25c8381c17df72f3d016d713aacc732b40a57163151d9cd406
6
+ metadata.gz: 314a64ec5dcf991328ef3ffcc1fdb18b5f99673bb1c27695d0e9f796ac922c26b0acb94517c146401dbb08d3e6adbc965c6e44b43ce13e22d0bbf8cf021a2b50
7
+ data.tar.gz: 0ed72bc6312ef1eae1059d5a93f530b056f9cec1ea7b690eaa93f1e6933be4dc4376cf2175f82846e8cf6dd49972714402ce3c539d76a1b828baffd915335905
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "activefacts-generators"
7
- spec.version = "1.8.2"
7
+ spec.version = "1.8.3"
8
8
  spec.authors = ["Clifford Heath"]
9
9
  spec.email = ["clifford.heath@gmail.com"]
10
10
 
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_development_dependency "bundler", ">= 1.10", "~> 1.10.6"
19
+ spec.add_development_dependency "bundler", ">= 1.10"
20
20
  spec.add_development_dependency "rake", "~> 10.0"
21
21
  spec.add_development_dependency "rspec", "~> 3.3"
22
22
 
@@ -2,29 +2,29 @@ module ActiveFacts
2
2
  module Generators
3
3
  module Rails
4
4
  module Helpers
5
- def rails_plural_name name
6
- # Crunch spaces and pluralise the first part, all in snake_case
7
- name.pop if name.is_a?(Array) and name.last == []
8
- name = name[0]*'_' if name.is_a?(Array) and name.size == 1
9
- if name.is_a?(Array)
10
- name = ActiveSupport::Inflector.tableize((name[0]*'_').gsub(/\s+/, '_')) +
11
- '_' +
12
- ActiveSupport::Inflector.underscore((name[1..-1].flatten*'_').gsub(/\s+/, '_'))
13
- else
14
- ActiveSupport::Inflector.tableize(name.gsub(/\s+/, '_'))
15
- end
16
- end
17
-
18
- def rails_singular_name name
19
- # Crunch spaces and convert to snake_case
20
- name = name.flatten*'_' if name.is_a?(Array)
21
- ActiveSupport::Inflector.underscore(name.gsub(/\s+/, '_'))
22
- end
23
-
24
- def rails_class_name name
25
- name = name*'_' if name.is_a?(Array)
26
- ActiveSupport::Inflector.camelize(name.gsub(/\s+/, '_'))
27
- end
5
+ def rails_plural_name name
6
+ # Crunch spaces and pluralise the first part, all in snake_case
7
+ name.pop if name.is_a?(Array) and name.last == []
8
+ name = name[0]*'_' if name.is_a?(Array) and name.size == 1
9
+ if name.is_a?(Array)
10
+ name = ActiveSupport::Inflector.tableize((name[0]*'_').gsub(/\s+/, '_')) +
11
+ '_' +
12
+ ActiveSupport::Inflector.underscore((name[1..-1].flatten*'_').gsub(/\s+/, '_'))
13
+ else
14
+ ActiveSupport::Inflector.tableize(name.gsub(/\s+/, '_'))
15
+ end
16
+ end
17
+
18
+ def rails_singular_name name
19
+ # Crunch spaces and convert to snake_case
20
+ name = name.flatten*'_' if name.is_a?(Array)
21
+ ActiveSupport::Inflector.underscore(name.gsub(/\s+/, '_'))
22
+ end
23
+
24
+ def rails_class_name name
25
+ name = name*'_' if name.is_a?(Array)
26
+ ActiveSupport::Inflector.camelize(name.gsub(/\s+/, '_'))
27
+ end
28
28
 
29
29
  end
30
30
  end
@@ -40,16 +40,16 @@ module ActiveFacts
40
40
  include Generate::Rails::Helpers
41
41
 
42
42
  def rails_from_association_name
43
- rails_singular_name(to_name.join('_'))
43
+ rails_singular_name(to_name.join('_'))
44
44
  end
45
45
 
46
46
  def rails_to_association
47
- jump = jump_reference
48
- if jump.is_one_to_one
49
- [ "has_one", rails_singular_name(from_name)]
50
- else
51
- [ "has_many", rails_plural_name(from_name)]
52
- end
47
+ jump = jump_reference
48
+ if jump.is_one_to_one
49
+ [ "has_one", rails_singular_name(from_name)]
50
+ else
51
+ [ "has_many", rails_plural_name(from_name)]
52
+ end
53
53
  end
54
54
 
55
55
  end
@@ -19,212 +19,212 @@ module ActiveFacts
19
19
  module Rails
20
20
  # Generate Rails models for the vocabulary
21
21
  # Invoke as
22
- # afgen --rails/schema[=options] <file>.cql
22
+ # afgen --rails/models[=options] <file>.cql
23
23
  class Models
24
24
 
25
- HEADER = "# Auto-generated from CQL, edits will be lost"
25
+ HEADER = "# Auto-generated from CQL, edits will be lost"
26
26
 
27
27
  private
28
28
 
29
- def initialize(vocabulary, *options)
30
- @vocabulary = vocabulary
31
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
32
- help if options.include? "help"
33
- options.delete_if { |option| @output = $1 if option =~ /^output=(.*)/ }
34
- @concern = nil
35
- options.delete_if { |option| @concern = $1 if option =~ /^concern=(.*)/ }
36
- @validations = true
37
- options.delete_if { |option| @validations = eval($1) if option =~ /^validation=(.*)/ }
38
- end
39
-
40
- def help
41
- @helping = true
42
- warn %Q{Options for --rails/schema:
43
- output=dir Overwrite model files into this output directory
44
- concern=name Namespace for the concerns
45
- validation=false Disable generation of validations
29
+ def initialize(vocabulary, *options)
30
+ @vocabulary = vocabulary
31
+ @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
32
+ help if options.include? "help"
33
+ options.delete_if { |option| @output = $1 if option =~ /^output=(.*)/ }
34
+ @concern = nil
35
+ options.delete_if { |option| @concern = $1 if option =~ /^concern=(.*)/ }
36
+ @validations = true
37
+ options.delete_if { |option| @validations = eval($1) if option =~ /^validation=(.*)/ }
38
+ end
39
+
40
+ def help
41
+ @helping = true
42
+ warn %Q{Options for --rails/schema:
43
+ output=dir Overwrite model files into this output directory
44
+ concern=name Namespace for the concerns
45
+ validation=false Disable generation of validations
46
46
  }
47
- end
47
+ end
48
48
 
49
- def warn *a
50
- $stderr.puts *a
51
- end
49
+ def warn *a
50
+ $stderr.puts *a
51
+ end
52
52
 
53
- def puts s
54
- @out.puts s
55
- end
53
+ def puts s
54
+ @out.puts s
55
+ end
56
56
 
57
57
  public
58
- def generate(out = $>) #:nodoc:
59
- return if @helping
60
- @out = out
61
- list_extant_files if @output
62
-
63
- # Populate all foreignkeys first:
64
- @vocabulary.tables.each { |table| table.foreign_keys }
65
- ok = true
66
- @vocabulary.tables.each do |table|
67
- ok &= generate_table(table)
68
- end
69
- $stderr.puts "\# #{@vocabulary.name} generated with errors" unless ok
70
- delete_old_generated_files if @output
71
- ok
72
- end
73
-
74
- def list_extant_files
75
- @preexisting_files = Dir[@output+'/*.rb']
76
- end
77
-
78
- def delete_old_generated_files
79
- remaining = []
80
- cleaned = 0
81
- @preexisting_files.each do |pathname|
82
- if generated_file_exists(pathname) == true
83
- File.unlink(pathname)
84
- cleaned += 1
85
- else
86
- remaining << pathname
87
- end
88
- end
89
- $stderr.puts "Cleaned up #{cleaned} old generated files" if @preexisting_files.size > 0
90
- $stderr.puts "Remaining non-generated files:\n\t#{remaining*"\n\t"}" if remaining.size > 0
91
- end
92
-
93
- def generated_file_exists pathname
94
- File.open(pathname, 'r') do |existing|
95
- first_lines = existing.read(1024) # Make it possible to pass over a magic charset comment
96
- if first_lines.length == 0 or first_lines =~ %r{^#{HEADER}}
97
- return true
98
- end
99
- end
100
- return false # File exists, but is not generated
101
- rescue Errno::ENOENT
102
- return nil # File does not exist
103
- end
104
-
105
- def create_if_ok filename
106
- # Create a file in the output directory, being careful not to overwrite carelessly
107
- if @output
108
- pathname = (@output+'/'+filename).gsub(%r{//+}, '/')
109
- @preexisting_files.reject!{|f| f == pathname } # Don't clean up this file
110
- if generated_file_exists(pathname) == false
111
- $stderr.puts "not overwriting non-generated file #{pathname}"
112
- @individual_file = nil
113
- return
114
- end
115
- @individual_file = @out = File.open(pathname, 'w')
116
- puts "#{HEADER}"
117
- end
118
- true
119
- end
120
-
121
- def to_associations table
122
- # belongs_to Associations
123
- table.foreign_keys.map do |fk|
124
- association_name = fk.rails_from_association_name
125
-
126
- if association_name != fk.to.rails_singular_name
127
- # A different class_name is implied, emit an explicit one:
128
- class_name = ", :class_name => '#{fk.to.rails_class_name}'"
129
- end
130
- foreign_key = ", :foreign_key => :#{fk.from_columns[0].rails_name}"
131
- if foreign_key == fk.to.rails_singular_name+'_id'
132
- # See lib/active_record/reflection.rb, method #derive_foreign_key
133
- foreign_key = ''
134
- end
135
-
136
- %Q{
58
+ def generate(out = $>) #:nodoc:
59
+ return if @helping
60
+ @out = out
61
+ list_extant_files if @output
62
+
63
+ # Populate all foreignkeys first:
64
+ @vocabulary.tables.each { |table| table.foreign_keys }
65
+ ok = true
66
+ @vocabulary.tables.each do |table|
67
+ ok &= generate_table(table)
68
+ end
69
+ warn "\# #{@vocabulary.name} generated with errors" unless ok
70
+ delete_old_generated_files if @output
71
+ ok
72
+ end
73
+
74
+ def list_extant_files
75
+ @preexisting_files = Dir[@output+'/*.rb']
76
+ end
77
+
78
+ def delete_old_generated_files
79
+ remaining = []
80
+ cleaned = 0
81
+ @preexisting_files.each do |pathname|
82
+ if generated_file_exists(pathname) == true
83
+ File.unlink(pathname)
84
+ cleaned += 1
85
+ else
86
+ remaining << pathname
87
+ end
88
+ end
89
+ $stderr.puts "Cleaned up #{cleaned} old generated files" if @preexisting_files.size > 0
90
+ $stderr.puts "Remaining non-generated files:\n\t#{remaining*"\n\t"}" if remaining.size > 0
91
+ end
92
+
93
+ def generated_file_exists pathname
94
+ File.open(pathname, 'r') do |existing|
95
+ first_lines = existing.read(1024) # Make it possible to pass over a magic charset comment
96
+ if first_lines.length == 0 or first_lines =~ %r{^#{HEADER}}
97
+ return true
98
+ end
99
+ end
100
+ return false # File exists, but is not generated
101
+ rescue Errno::ENOENT
102
+ return nil # File does not exist
103
+ end
104
+
105
+ def create_if_ok filename
106
+ # Create a file in the output directory, being careful not to overwrite carelessly
107
+ if @output
108
+ pathname = (@output+'/'+filename).gsub(%r{//+}, '/')
109
+ @preexisting_files.reject!{|f| f == pathname } # Don't clean up this file
110
+ if generated_file_exists(pathname) == false
111
+ $stderr.puts "not overwriting non-generated file #{pathname}"
112
+ @individual_file = nil
113
+ return
114
+ end
115
+ @individual_file = @out = File.open(pathname, 'w')
116
+ puts "#{HEADER}"
117
+ end
118
+ true
119
+ end
120
+
121
+ def to_associations table
122
+ # belongs_to Associations
123
+ table.foreign_keys.map do |fk|
124
+ association_name = fk.rails_from_association_name
125
+
126
+ if association_name != fk.to.rails_singular_name
127
+ # A different class_name is implied, emit an explicit one:
128
+ class_name = ", :class_name => '#{fk.to.rails_class_name}'"
129
+ end
130
+ foreign_key = ", :foreign_key => :#{fk.from_columns[0].rails_name}"
131
+ if foreign_key == fk.to.rails_singular_name+'_id'
132
+ # See lib/active_record/reflection.rb, method #derive_foreign_key
133
+ foreign_key = ''
134
+ end
135
+
136
+ %Q{
137
137
  \# #{fk.verbalised_path}
138
138
  belongs_to :#{association_name}#{class_name}#{foreign_key}}
139
- end
140
- end
141
-
142
- def from_associations table
143
- # has_one/has_many Associations
144
- table.foreign_keys_to.sort_by{|fk| fk.describe}.map do |fk|
145
- # Get the jump reference
146
-
147
- if fk.from_columns.size > 1
148
- raise "Can't emit Rails associations for multi-part foreign key with #{fk.references.inspect}. Did you mean to use --transform/surrogate"
149
- end
150
-
151
- association_type, association_name = *fk.rails_to_association
152
-
153
- ref = fk.jump_reference
154
- [
155
- "\n \# #{fk.verbalised_path(true)}" +
156
- "\n" +
157
- %Q{ #{association_type} :#{association_name}} +
158
- %Q{, :class_name => '#{fk.from.rails_class_name}'} +
159
- %Q{, :foreign_key => :#{fk.from_columns[0].rails_name}} +
160
- %Q{, :dependent => :destroy}
161
- ] +
162
- # If ref.from is a join table, we can emit a has_many :through for each other key
163
- # REVISIT Could alternately do this for all belongs_to's in ref.from
164
- if ref.from.identifier_columns.length > 1
165
- ref.from.identifier_columns.map do |ic|
166
- next nil if ic.references[0] == ref or # Skip the back-reference
167
- ic.references[0].is_unary # or use rails_plural_name(ic.references[0].to_names) ?
168
- # This far association name needs to be augmented for its role name
169
- far_association_name = ic.references[0].to.rails_name
170
- %Q{ has_many :#{far_association_name}, :through => :#{association_name}} # \# via #{ic.name}}
171
- end
172
- else
173
- []
174
- end
175
- end.flatten.compact
176
- end
177
-
178
- def column_constraints table
179
- return [] unless @validations
180
- ccs =
181
- table.columns.map do |column|
182
- name = column.rails_name
183
- column.is_mandatory &&
184
- !column.is_auto_assigned && !column.is_auto_timestamp ? [
185
- " validates :#{name}, :presence => true"
186
- ] : []
187
- end.flatten
188
- ccs.unshift("") unless ccs.empty?
189
- ccs
190
- end
191
-
192
- def model_body table
193
- %Q{module #{table.rails_class_name}
139
+ end
140
+ end
141
+
142
+ def from_associations table
143
+ # has_one/has_many Associations
144
+ table.foreign_keys_to.sort_by{|fk| fk.describe}.map do |fk|
145
+ # Get the jump reference
146
+
147
+ if fk.from_columns.size > 1
148
+ raise "Can't emit Rails associations for multi-part foreign key with #{fk.references.inspect}. Did you mean to use --transform/surrogate"
149
+ end
150
+
151
+ association_type, association_name = *fk.rails_to_association
152
+
153
+ ref = fk.jump_reference
154
+ [
155
+ "\n \# #{fk.verbalised_path(true)}" +
156
+ "\n" +
157
+ %Q{ #{association_type} :#{association_name}} +
158
+ %Q{, :class_name => '#{fk.from.rails_class_name}'} +
159
+ %Q{, :foreign_key => :#{fk.from_columns[0].rails_name}} +
160
+ %Q{, :dependent => :destroy}
161
+ ] +
162
+ # If ref.from is a join table, we can emit a has_many :through for each other key
163
+ # REVISIT Could alternately do this for all belongs_to's in ref.from
164
+ if ref.from.identifier_columns.length > 1
165
+ ref.from.identifier_columns.map do |ic|
166
+ next nil if ic.references[0] == ref or # Skip the back-reference
167
+ ic.references[0].is_unary # or use rails_plural_name(ic.references[0].to_names) ?
168
+ # This far association name needs to be augmented for its role name
169
+ far_association_name = ic.references[0].to.rails_name
170
+ %Q{ has_many :#{far_association_name}, :through => :#{association_name}} # \# via #{ic.name}}
171
+ end
172
+ else
173
+ []
174
+ end
175
+ end.flatten.compact
176
+ end
177
+
178
+ def column_constraints table
179
+ return [] unless @validations
180
+ ccs =
181
+ table.columns.map do |column|
182
+ name = column.rails_name
183
+ column.is_mandatory &&
184
+ !column.is_auto_assigned && !column.is_auto_timestamp ? [
185
+ " validates :#{name}, :presence => true"
186
+ ] : []
187
+ end.flatten
188
+ ccs.unshift("") unless ccs.empty?
189
+ ccs
190
+ end
191
+
192
+ def model_body table
193
+ %Q{module #{table.rails_class_name}
194
194
  extend ActiveSupport::Concern
195
195
  included do} +
196
- (table.identifier_columns.length == 1 ? %Q{
196
+ (table.identifier_columns.length == 1 ? %Q{
197
197
  self.primary_key = '#{table.identifier_columns[0].rails_name}'
198
198
  } : ''
199
- ) +
200
-
201
- (
202
- to_associations(table) +
203
- from_associations(table) +
204
- column_constraints(table)
205
- ) * "\n" +
206
- %Q{
199
+ ) +
200
+
201
+ (
202
+ to_associations(table) +
203
+ from_associations(table) +
204
+ column_constraints(table)
205
+ ) * "\n" +
206
+ %Q{
207
207
  end
208
208
  end
209
209
  }
210
- end
210
+ end
211
211
 
212
- def generate_table table
213
- old_out = @out
214
- filename = table.rails_singular_name+'.rb'
212
+ def generate_table table
213
+ old_out = @out
214
+ filename = table.rails_singular_name+'.rb'
215
215
 
216
- return unless create_if_ok filename
216
+ return unless create_if_ok filename
217
217
 
218
- puts "\n"
219
- puts "module #{@concern}" if @concern
220
- puts model_body(table).gsub(/^./, @concern ? ' \0' : '\0')
221
- puts 'end' if @concern
218
+ puts "\n"
219
+ puts "module #{@concern}" if @concern
220
+ puts model_body(table).gsub(/^./, @concern ? ' \0' : '\0')
221
+ puts 'end' if @concern
222
222
 
223
- true # We succeeded
224
- ensure
225
- @out = old_out
226
- @individual_file.close if @individual_file
227
- end
223
+ true # We succeeded
224
+ ensure
225
+ @out = old_out
226
+ @individual_file.close if @individual_file
227
+ end
228
228
 
229
229
  end
230
230
  end
@@ -233,12 +233,12 @@ end
233
233
  module RMap
234
234
  class Column
235
235
  def is_auto_timestamp
236
- case name('_')
237
- when /\A(created|updated)_(at|on)\Z/i
238
- true
239
- else
240
- false
241
- end
236
+ case name('_')
237
+ when /\A(created|updated)_(at|on)\Z/i
238
+ true
239
+ else
240
+ false
241
+ end
242
242
  end
243
243
  end
244
244
  end
@@ -17,197 +17,197 @@ module ActiveFacts
17
17
  # afgen --rails/schema[=options] <file>.cql
18
18
  class SchemaRb
19
19
  private
20
- include RMap
21
-
22
- def initialize(vocabulary, *options)
23
- @vocabulary = vocabulary
24
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
25
- help if options.include? "help"
26
- @exclude_fks = options.include? "exclude_fks"
27
- @include_comments = options.include? "include_comments"
28
- @closed_world = options.include? "closed_world"
29
- end
30
-
31
- def help
32
- @helping = true
33
- warn %Q{Options for --rails/schema:
34
- exclude_fks Don't generate foreign key definitions for use with Rails 4 or the foreigner gem
35
- include_comments Generate a comment for each column showing the absorption path
36
- closed_world Set this if your DBMS only allows one null in a unique index (MS SQL)
20
+ include RMap
21
+
22
+ def initialize(vocabulary, *options)
23
+ @vocabulary = vocabulary
24
+ @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
25
+ help if options.include? "help"
26
+ @exclude_fks = options.include? "exclude_fks"
27
+ @include_comments = options.include? "include_comments"
28
+ @closed_world = options.include? "closed_world"
29
+ end
30
+
31
+ def help
32
+ @helping = true
33
+ warn %Q{Options for --rails/schema:
34
+ exclude_fks Don't generate foreign key definitions for use with Rails 4 or the foreigner gem
35
+ include_comments Generate a comment for each column showing the absorption path
36
+ closed_world Set this if your DBMS only allows one null in a unique index (MS SQL)
37
37
  }
38
- end
38
+ end
39
39
 
40
- def warn *a
41
- $stderr.puts *a
42
- end
40
+ def warn *a
41
+ $stderr.puts *a
42
+ end
43
43
 
44
- def puts s
45
- @out.puts s
46
- end
44
+ def puts s
45
+ @out.puts s
46
+ end
47
47
 
48
48
  public
49
49
 
50
- # We sort the columns here, not in the rmap layer, because it affects
51
- # the ordering of columns in an index :-(.
52
- def sorted_columns table, pk, fk_columns
53
- table.columns.sort_by do |column|
54
- [ # Emit columns alphabetically, but PK first, then FKs, then others
55
- case
56
- when i = pk.index(column)
57
- i
58
- when fk_columns.include?(column)
59
- pk.size+1
60
- else
61
- pk.size+2
62
- end,
63
- column.rails_name
64
- ]
65
- end
66
- end
67
-
68
- def generate_column table, pk, column
69
- name = column.rails_name
70
- type, params, constraints = *column.type
71
- length = params[:length]
72
- length &&= length.to_i
73
- scale = params[:scale]
74
- scale &&= scale.to_i
75
- rails_type, length = *column.rails_type
50
+ # We sort the columns here, not in the rmap layer, because it affects
51
+ # the ordering of columns in an index :-(.
52
+ def sorted_columns table, pk, fk_columns
53
+ table.columns.sort_by do |column|
54
+ [ # Emit columns alphabetically, but PK first, then FKs, then others
55
+ case
56
+ when i = pk.index(column)
57
+ i
58
+ when fk_columns.include?(column)
59
+ pk.size+1
60
+ else
61
+ pk.size+2
62
+ end,
63
+ column.rails_name
64
+ ]
65
+ end
66
+ end
67
+
68
+ def generate_column table, pk, column
69
+ name = column.rails_name
70
+ type, params, constraints = *column.type
71
+ length = params[:length]
72
+ length &&= length.to_i
73
+ scale = params[:scale]
74
+ scale &&= scale.to_i
75
+ rails_type, length = *column.rails_type
76
76
 
77
- length_name = rails_type == 'decimal' ? 'precision' : 'limit'
78
- length_option = length ? ", :#{length_name} => #{length}" : ''
79
- scale_option = scale ? ", :scale => #{scale}" : ''
80
-
81
- comment = column.comment
82
- null_option = ", :null => #{!column.is_mandatory}"
83
- if pk.size == 1 && pk[0] == column
84
- case rails_type
85
- when 'serial'
86
- rails_type = "primary_key"
87
- when 'uuid'
88
- rails_type = "uuid, :default => 'gen_random_uuid()', :primary_key => true"
89
- end
90
- else
91
- case rails_type
92
- when 'serial'
93
- rails_type = 'integer' # An integer foreign key
94
- end
95
- end
96
-
97
- (@include_comments ? [" \# #{comment}"] : []) +
98
- [
99
- %Q{ t.column "#{name}", :#{rails_type}#{length_option}#{scale_option}#{null_option}}
100
- ]
101
- end
102
-
103
- def generate_columns table, pk, fk_columns
104
- sc = sorted_columns(table, pk, fk_columns)
105
- lines = sc.map do |column|
106
- generate_column table, pk, column
107
- end
108
- lines.flatten
109
- end
110
-
111
- def generate_table table, foreign_keys
112
- ar_table_name = table.rails_name
113
-
114
- pk = table.identifier_columns
115
- if pk[0].is_auto_assigned
116
- identity_column = pk[0]
117
- warn "Warning: redundant column(s) after #{identity_column.name} in primary key of #{ar_table_name}" if pk.size > 1
118
- end
119
-
120
- # Get the list of references that give rise to foreign keys:
121
- fk_refs = table.references_from.select{|ref| ref.is_simple_reference }
122
-
123
- # Get the list of columns that embody the foreign keys:
124
- fk_columns = table.columns.select do |column|
125
- column.references[0].is_simple_reference
126
- end
127
-
128
- # Detect if this table is a join table.
129
- # Join tables have multi-part primary keys that are made up only of foreign keys
130
- is_join_table = pk.length > 1 and
131
- !pk.detect do |pk_column|
132
- !fk_columns.include?(pk_column)
133
- end
134
- warn "Warning: #{table.name} has a multi-part primary key" if pk.length > 1 and !is_join_table
135
-
136
- puts %Q{ create_table "#{ar_table_name}", :id => false, :force => true do |t|}
137
-
138
- columns = generate_columns table, pk, fk_columns
139
-
140
- unless @exclude_fks
141
- table.foreign_keys.each do |fk|
142
- from_columns = fk.from_columns.map{|column| column.rails_name}
143
- to_columns = fk.to_columns.map{|column| column.rails_name}
144
-
145
- foreign_keys.concat(
146
- if (from_columns.length == 1)
147
- index_name = RMap.rails_name_trunc('index_'+fk.from.rails_name+'_on_'+from_columns[0])
148
- [
149
- " add_foreign_key :#{fk.from.rails_name}, :#{fk.to.rails_name}, :column => :#{from_columns[0]}, :primary_key => :#{to_columns[0]}, :on_delete => :cascade"
150
- ]+
151
- Array(
152
- # Index it non-uniquely only if it's not unique already:
153
- fk.jump_reference.to_role.is_unique ? nil :
154
- " add_index :#{fk.from.rails_name}, [:#{from_columns[0]}], :unique => false, :name => :#{index_name}"
155
- )
156
- else
157
- # This probably isn't going to work without Dr Nic's CPK gem:
158
- [
159
- " add_foreign_key :#{fk.to.rails_name}, :#{fk.from.rails_name}, :column => [:#{from_columns.join(':, ')}], :primary_key => [:#{to_columns.join(':, ')}], :on_delete => :cascade"
160
- ]
161
- end
162
- )
163
- end
164
- end
165
-
166
- indices = table.indices
167
- index_text = []
168
- indices.each do |index|
169
- next if index.is_primary && index.columns.size == 1 # We've handled this already
170
-
171
- index_name = index.rails_name
172
-
173
- unique = !index.columns.detect{|column| !column.is_mandatory} and !@closed_world
174
- index_text << %Q{ add_index "#{ar_table_name}", ["#{index.columns.map{|c| c.rails_name}*'", "'}"], :name => :#{index_name}#{
175
- unique ? ", :unique => true" : ''
176
- }}
177
- end
178
-
179
- puts columns.join("\n")
180
- puts " end\n\n"
181
-
182
- puts index_text.join("\n")
183
- puts "\n" unless index_text.empty?
184
- end
185
-
186
- def generate(out = $>) #:nodoc:
187
- return if @helping
188
- @out = out
189
-
190
- foreign_keys = []
191
-
192
- # If we get index names that need to be truncated, add a counter to ensure uniqueness
193
- dup_id = 0
194
-
195
- puts "#\n# schema.rb auto-generated using ActiveFacts for #{@vocabulary.name} on #{Date.today}\n#\n\n"
196
- puts "ActiveRecord::Base.logger = Logger.new(STDOUT)\n"
197
- puts "ActiveRecord::Schema.define(:version => #{Time.now.strftime('%Y%m%d%H%M%S')}) do"
198
- puts " enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')\n"
199
-
200
- @vocabulary.tables.each do |table|
201
- generate_table table, foreign_keys
202
- end
203
-
204
- unless @exclude_fks
205
- puts ' unless ENV["EXCLUDE_FKS"]'
206
- puts foreign_keys.join("\n")
207
- puts ' end'
208
- end
209
- puts "end"
210
- end
77
+ length_name = rails_type == 'decimal' ? 'precision' : 'limit'
78
+ length_option = length ? ", #{length_name}: #{length}" : ''
79
+ scale_option = scale ? ", scale: #{scale}" : ''
80
+
81
+ comment = column.comment
82
+ null_option = ", null: #{!column.is_mandatory}"
83
+ if pk.size == 1 && pk[0] == column
84
+ case rails_type
85
+ when 'serial'
86
+ rails_type = "primary_key"
87
+ when 'uuid'
88
+ rails_type = "uuid, default: 'gen_random_uuid()', primary_key: true"
89
+ end
90
+ else
91
+ case rails_type
92
+ when 'serial'
93
+ rails_type = 'integer' # An integer foreign key
94
+ end
95
+ end
96
+
97
+ (@include_comments ? [" \# #{comment}"] : []) +
98
+ [
99
+ %Q{ t.column "#{name}", :#{rails_type}#{length_option}#{scale_option}#{null_option}}
100
+ ]
101
+ end
102
+
103
+ def generate_columns table, pk, fk_columns
104
+ sc = sorted_columns(table, pk, fk_columns)
105
+ lines = sc.map do |column|
106
+ generate_column table, pk, column
107
+ end
108
+ lines.flatten
109
+ end
110
+
111
+ def generate_table table, foreign_keys
112
+ ar_table_name = table.rails_name
113
+
114
+ pk = table.identifier_columns
115
+ if pk[0].is_auto_assigned
116
+ identity_column = pk[0]
117
+ warn "Warning: redundant column(s) after #{identity_column.name} in primary key of #{ar_table_name}" if pk.size > 1
118
+ end
119
+
120
+ # Get the list of references that give rise to foreign keys:
121
+ fk_refs = table.references_from.select{|ref| ref.is_simple_reference }
122
+
123
+ # Get the list of columns that embody the foreign keys:
124
+ fk_columns = table.columns.select do |column|
125
+ column.references[0].is_simple_reference
126
+ end
127
+
128
+ # Detect if this table is a join table.
129
+ # Join tables have multi-part primary keys that are made up only of foreign keys
130
+ is_join_table = pk.length > 1 and
131
+ !pk.detect do |pk_column|
132
+ !fk_columns.include?(pk_column)
133
+ end
134
+ warn "Warning: #{table.name} has a multi-part primary key" if pk.length > 1 and !is_join_table
135
+
136
+ puts %Q{ create_table "#{ar_table_name}", id: false, force: true do |t|}
137
+
138
+ columns = generate_columns table, pk, fk_columns
139
+
140
+ unless @exclude_fks
141
+ table.foreign_keys.each do |fk|
142
+ from_columns = fk.from_columns.map{|column| column.rails_name}
143
+ to_columns = fk.to_columns.map{|column| column.rails_name}
144
+
145
+ foreign_keys.concat(
146
+ if (from_columns.length == 1)
147
+ index_name = RMap.rails_name_trunc('index_'+fk.from.rails_name+'_on_'+from_columns[0])
148
+ [
149
+ " add_foreign_key :#{fk.from.rails_name}, :#{fk.to.rails_name}, column: :#{from_columns[0]}, primary_key: :#{to_columns[0]}, on_delete: :cascade"
150
+ ]+
151
+ Array(
152
+ # Index it non-uniquely only if it's not unique already:
153
+ fk.jump_reference.to_role.is_unique ? nil :
154
+ " add_index :#{fk.from.rails_name}, [:#{from_columns[0]}], unique: false, name: :#{index_name}"
155
+ )
156
+ else
157
+ # This probably isn't going to work without Dr Nic's CPK gem:
158
+ [
159
+ " add_foreign_key :#{fk.to.rails_name}, :#{fk.from.rails_name}, column: [:#{from_columns.join(':, ')}], primary_key: [:#{to_columns.join(':, ')}], on_delete: :cascade"
160
+ ]
161
+ end
162
+ )
163
+ end
164
+ end
165
+
166
+ indices = table.indices
167
+ index_text = []
168
+ indices.each do |index|
169
+ next if index.is_primary && index.columns.size == 1 # We've handled this already
170
+
171
+ index_name = index.rails_name
172
+
173
+ unique = !index.columns.detect{|column| !column.is_mandatory} and !@closed_world
174
+ index_text << %Q{ add_index "#{ar_table_name}", ["#{index.columns.map{|c| c.rails_name}*'", "'}"], name: :#{index_name}#{
175
+ unique ? ", unique: true" : ''
176
+ }}
177
+ end
178
+
179
+ puts columns.join("\n")
180
+ puts " end\n\n"
181
+
182
+ puts index_text.join("\n")
183
+ puts "\n" unless index_text.empty?
184
+ end
185
+
186
+ def generate(out = $>) #:nodoc:
187
+ return if @helping
188
+ @out = out
189
+
190
+ foreign_keys = []
191
+
192
+ # If we get index names that need to be truncated, add a counter to ensure uniqueness
193
+ dup_id = 0
194
+
195
+ puts "#\n# schema.rb auto-generated using ActiveFacts for #{@vocabulary.name} on #{Date.today}\n#\n\n"
196
+ puts "ActiveRecord::Base.logger = Logger.new(STDOUT)\n"
197
+ puts "ActiveRecord::Schema.define(version: #{Time.now.strftime('%Y%m%d%H%M%S')}) do"
198
+ puts " enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')\n"
199
+
200
+ @vocabulary.tables.each do |table|
201
+ generate_table table, foreign_keys
202
+ end
203
+
204
+ unless @exclude_fks
205
+ puts ' unless ENV["EXCLUDE_FKS"]'
206
+ puts foreign_keys.join("\n")
207
+ puts ' end'
208
+ end
209
+ puts "end"
210
+ end
211
211
 
212
212
  end
213
213
  end
@@ -195,6 +195,9 @@ module ActiveFacts
195
195
  :fact_type => ref.fact_type,
196
196
  :concept => :new
197
197
  )
198
+
199
+ # REVISIT: Objectifying requires creation of LinkFactTypes.
200
+
198
201
  @link_tables << et
199
202
  end
200
203
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activefacts-generators
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.2
4
+ version: 1.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clifford Heath
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-16 00:00:00.000000000 Z
11
+ date: 2016-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -17,9 +17,6 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.10'
20
- - - "~>"
21
- - !ruby/object:Gem::Version
22
- version: 1.10.6
23
20
  type: :development
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
@@ -27,9 +24,6 @@ dependencies:
27
24
  - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '1.10'
30
- - - "~>"
31
- - !ruby/object:Gem::Version
32
- version: 1.10.6
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: rake
35
29
  requirement: !ruby/object:Gem::Requirement