Class: ActiveFacts::Generate::Rails::Models
- Inherits:
-
Object
- Object
- ActiveFacts::Generate::Rails::Models
- Defined in:
- lib/activefacts/generate/rails/models.rb
Overview
Generate Rails models for the vocabulary Invoke as
afgen --rails/schema[=options] <file>.cql
Constant Summary collapse
- HEADER =
"# Auto-generated from CQL, edits will be lost"
Instance Method Summary collapse
- #column_constraints(table) ⇒ Object
- #create_if_ok(filename) ⇒ Object
- #delete_old_generated_files ⇒ Object
- #from_associations(table) ⇒ Object
-
#generate(out = $>) ⇒ Object
:nodoc:.
- #generate_table(table) ⇒ Object
- #generated_file_exists(pathname) ⇒ Object
- #list_extant_files ⇒ Object
- #model_body(table) ⇒ Object
- #to_associations(table) ⇒ Object
Instance Method Details
#column_constraints(table) ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/activefacts/generate/rails/models.rb', line 175 def column_constraints table return [] unless @validations ccs = table.columns.map do |column| name = column.rails_name column.is_mandatory && !column.is_auto_assigned && !column. ? [ " validates :#{name}, :presence => true" ] : [] end.flatten ccs.unshift("") unless ccs.empty? ccs end |
#create_if_ok(filename) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/activefacts/generate/rails/models.rb', line 104 def create_if_ok filename # Create a file in the output directory, being careful not to overwrite carelessly if @output pathname = (@output+'/'+filename).gsub(%r{//+}, '/') @preexisting_files.reject!{|f| f == pathname } # Don't clean up this file if generated_file_exists(pathname) == false $stderr.puts "not overwriting non-generated file #{pathname}" @individual_file = nil return end @individual_file = @out = File.open(pathname, 'w') puts "#{HEADER}" end true end |
#delete_old_generated_files ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/activefacts/generate/rails/models.rb', line 77 def delete_old_generated_files remaining = [] cleaned = 0 @preexisting_files.each do |pathname| if generated_file_exists(pathname) == true File.unlink(pathname) cleaned += 1 else remaining << pathname end end $stderr.puts "Cleaned up #{cleaned} old generated files" if @preexisting_files.size > 0 $stderr.puts "Remaining non-generated files:\n\t#{remaining*"\n\t"}" if remaining.size > 0 end |
#from_associations(table) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/activefacts/generate/rails/models.rb', line 139 def from_associations table # has_one/has_many Associations table.foreign_keys_to.sort_by{|fk| fk.describe}.map do |fk| # Get the jump reference if fk.from_columns.size > 1 raise "Can't emit Rails associations for multi-part foreign key with #{fk.references.inspect}. Did you mean to use --transform/surrogate" end association_type, association_name = *fk.rails_to_association ref = fk.jump_reference [ "\n \# #{fk.verbalised_path}" + "\n" + %Q{ #{association_type} :#{association_name}} + %Q{, :class_name => '#{fk.from.rails_class_name}'} + %Q{, :foreign_key => :#{fk.from_columns[0].rails_name}} + %Q{, :dependent => :destroy} ] + # If ref.from is a join table, we can emit a has_many :through for each other key # REVISIT Could alternately do this for all belongs_to's in ref.from if ref.from.identifier_columns.length > 1 ref.from.identifier_columns.map do |ic| next nil if ic.references[0] == ref or # Skip the back-reference ic.references[0].is_unary # or use rails_plural_name(ic.references[0].to_names) ? # This far association name needs to be augmented for its role name far_association_name = ic.references[0].to.rails_name %Q{ has_many :#{far_association_name}, :through => :#{association_name}} # \# via #{ic.name}} end else [] end end.flatten.compact end |
#generate(out = $>) ⇒ Object
:nodoc:
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/activefacts/generate/rails/models.rb', line 57 def generate(out = $>) #:nodoc: return if @helping @out = out list_extant_files if @output # Populate all foreignkeys first: @vocabulary.tables.each { |table| table.foreign_keys } ok = true @vocabulary.tables.each do |table| ok &= generate_table(table) end $stderr.puts "\# #{@vocabulary.name} generated with errors" unless ok delete_old_generated_files if @output ok end |
#generate_table(table) ⇒ Object
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/activefacts/generate/rails/models.rb', line 209 def generate_table table old_out = @out filename = table.rails_singular_name+'.rb' return unless create_if_ok filename puts "\n" puts "module #{@concern}" if @concern puts model_body(table).gsub(/^./, @concern ? ' \0' : '\0') puts 'end' if @concern true # We succeeded ensure @out = old_out @individual_file.close if @individual_file end |
#generated_file_exists(pathname) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/activefacts/generate/rails/models.rb', line 92 def generated_file_exists pathname File.open(pathname, 'r') do |existing| first_lines = existing.read(1024) # Make it possible to pass over a magic charset comment if first_lines.length == 0 or first_lines =~ %r{^#{HEADER}} return true end end return false # File exists, but is not generated rescue Errno::ENOENT return nil # File does not exist end |
#list_extant_files ⇒ Object
73 74 75 |
# File 'lib/activefacts/generate/rails/models.rb', line 73 def list_extant_files @preexisting_files = Dir[@output+'/*.rb'] end |
#model_body(table) ⇒ Object
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/activefacts/generate/rails/models.rb', line 189 def model_body table %Q{module #{table.rails_class_name} extend ActiveSupport::Concern included do} + (table.identifier_columns.length == 1 ? %Q{ self.primary_key = '#{table.identifier_columns[0].rails_name}' } : '' ) + ( to_associations(table) + from_associations(table) + column_constraints(table) ) * "\n" + %Q{ end end } end |
#to_associations(table) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/activefacts/generate/rails/models.rb', line 120 def to_associations table # belongs_to Associations table.foreign_keys.map do |fk| association_name = fk.rails_from_association_name foreign_key = "" if association_name != fk.to.rails_singular_name # A different class_name is implied, emit an explicit one: class_name = ", :class_name => '#{fk.to.rails_class_name}'" from_column = fk.from_columns foreign_key = ", :foreign_key => :#{fk.from_columns[0].rails_name}" end %Q{ \# #{fk.verbalised_path} belongs_to :#{association_name}#{class_name}#{foreign_key}} end end |