Class: ActiveFacts::Generators::Rails::Models
- Inherits:
-
Object
- Object
- ActiveFacts::Generators::Rails::Models
- Defined in:
- lib/activefacts/generators/rails/models.rb
Overview
Generate Rails models for the vocabulary Invoke as
afgen --rails/models[=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
178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/activefacts/generators/rails/models.rb', line 178 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
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/activefacts/generators/rails/models.rb', line 105 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
78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/activefacts/generators/rails/models.rb', line 78 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
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 174 175 176 |
# File 'lib/activefacts/generators/rails/models.rb', line 142 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(true)}" + "\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:
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/activefacts/generators/rails/models.rb', line 58 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 warn "\# #{@vocabulary.name} generated with errors" unless ok delete_old_generated_files if @output ok end |
#generate_table(table) ⇒ Object
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/activefacts/generators/rails/models.rb', line 212 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
93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/activefacts/generators/rails/models.rb', line 93 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
74 75 76 |
# File 'lib/activefacts/generators/rails/models.rb', line 74 def list_extant_files @preexisting_files = Dir[@output+'/*.rb'] end |
#model_body(table) ⇒ Object
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/activefacts/generators/rails/models.rb', line 192 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
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/activefacts/generators/rails/models.rb', line 121 def to_associations table # belongs_to Associations table.foreign_keys.map do |fk| association_name = fk.rails_from_association_name 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}'" end foreign_key = ", :foreign_key => :#{fk.from_columns[0].rails_name}" if foreign_key == fk.to.rails_singular_name+'_id' # See lib/active_record/reflection.rb, method #derive_foreign_key foreign_key = '' end %Q{ \# #{fk.verbalised_path} belongs_to :#{association_name}#{class_name}#{foreign_key}} end end |