lib/activefacts/generate/ruby.rb in activefacts-0.8.16 vs lib/activefacts/generate/ruby.rb in activefacts-0.8.18

- old
+ new

@@ -2,50 +2,65 @@ # ActiveFacts Generators. # Generate Ruby classes for the ActiveFacts API from an ActiveFacts vocabulary. # # Copyright (c) 2009 Clifford Heath. Read the LICENSE file. # +require 'activefacts' require 'activefacts/vocabulary' -require 'activefacts/generate/oo' +require 'activefacts/generate/helpers/oo' +require 'activefacts/mapping/rails' module ActiveFacts module Generate # Generate Ruby module containing classes for an ActiveFacts vocabulary. # Invoke as # afgen --ruby[=options] <file>.cql # Options are comma or space separated: # * help list available options # * sql Emit the sql mapping for tables/columns (REVISIT: not functional at present) - class RUBY < OO + class RUBY < Helpers::OO private def set_option(option) - @sql ||= false + @mapping = false case option when 'help', '?' $stderr.puts "Usage:\t\tafgen --ruby[=option,option] input_file.cql\n"+ - "options:\tsql\tEmit data to enable mappings to SQL" + "\t\tmapping={sql|rails}\tEmit data to enable mappings to SQL or to Rails" exit 0 - when 'sql'; @sql = true + when /mapping=(.*)/ + @mapping = $1 + @vocabulary.tables else super end end def vocabulary_start(vocabulary) puts "require 'activefacts/api'\n" - if @sql + if @mapping require 'activefacts/persistence' + end + if @mapping == 'sql' puts "require 'activefacts/persistence'\n" @tables = vocabulary.tables end puts "\nmodule ::#{vocabulary.name}\n\n" end def vocabulary_end puts "end" end + def emit_mapping o + case @mapping + when 'sql' + puts " table" + when 'rails' + puts " table :#{o.rails_name}" + end + end + def value_type_dump(o) length = (l = o.length) && l > 0 ? ":length => #{l}" : nil scale = (s = o.scale) && s > 0 ? ":scale => #{s}" : nil params = [length,scale].compact * ", " @@ -67,13 +82,11 @@ ruby_type_name = '::'+ruby_type_name end puts " class #{name} < #{ruby_type_name}\n" + " value_type #{params}\n" - if @sql and o.is_table - puts " table" - end + emit_mapping o if o.is_table puts " restrict #{o.value_constraint.all_allowed_range_sorted.map{|ar| ar.to_s}*", "}\n" if o.value_constraint puts " \# REVISIT: #{o.name} is in units of #{o.unit.name}\n" if o.unit roles_dump(o) puts " end\n\n" end @@ -83,13 +96,11 @@ secondary_supertypes = o.supertypes-[primary_supertype] puts " class #{o.name.gsub(/ /,'')} < #{ primary_supertype.name.gsub(/ /,'') }" puts " identified_by #{identified_by(o, pi)}" if pi puts " supertypes "+secondary_supertypes.map{|st| st.name.gsub(/ /,'')}*", " if secondary_supertypes.size > 0 - if @sql and o.is_table - puts " table" - end + emit_mapping(o) if o.is_table fact_roles_dump(o.fact_type) if o.fact_type roles_dump(o) puts " end\n\n" @constraints_used[pi] = true if pi end @@ -97,13 +108,11 @@ def non_subtype_dump(o, pi) puts " class #{o.name.gsub(/ /,'')}" # We want to name the absorption role only when it's absorbed along its single identifying role. puts " identified_by #{identified_by(o, pi)}" - if @sql and o.is_table - puts " table" - end + emit_mapping o if o.is_table fact_roles_dump(o.fact_type) if o.fact_type roles_dump(o) puts " end\n\n" @constraints_used[pi] = true end @@ -123,11 +132,11 @@ puts " class #{name.gsub(/ /,'')}" + (primary_supertype ? " < "+primary_supertype.name.gsub(/ /,'') : "") + "\n" + secondary_supertypes.map{|sst| " supertype :#{sst.name.gsub(/ /,'_')}"}*"\n" + (pi ? " identified_by #{identified_by(o, pi)}" : "") - puts " table" if @sql and o.is_table + emit_mapping o if o.is_table fact_roles_dump(fact_type) roles_dump(o) puts " end\n\n" @fact_types_dumped[fact_type] = true @@ -142,29 +151,39 @@ def unary_dump(role, role_name) puts " maybe :"+role_name end def binary_dump(role, role_name, role_player, mandatory = nil, one_to_one = nil, readings = nil, other_role_name = nil, other_method_name = nil) + ruby_role_name = ":"+role_name.gsub(/ /,'_') + # Find whether we need the name of the other role player, and whether it's defined yet: - if role_name.camelcase == role_player.name.gsub(/ /,'').sub(/^[a-z]/) {|i| i.upcase} - # Don't use Class name if implied by rolename - role_reference = nil - else + implied_role_name = role_player.name.gsub(/ /,'').sub(/^[a-z]/) {|i| i.upcase} + if role_name.camelcase != implied_role_name + # Only use Class name if it's not implied by the rolename role_reference = ":class => "+object_type_reference(role_player) end + other_role_name = ":counterpart => :"+other_role_name.gsub(/ /,'_') if other_role_name - line = " #{one_to_one ? "one_to_one" : "has_one" } " + - [ ":"+role_name.gsub(/ /,'_'), - role_reference, - mandatory ? ":mandatory => true" : nil, - readings, - other_role_name, - (vr = role.role_value_constraint) ? ":restrict => #{vr}" : nil - ].compact*", "+" " - line += " "*(48-line.length) if line.length < 48 - line += "\# See #{role_player.name.gsub(/ /,'')}.#{other_method_name}" if other_method_name + if vr = role.role_value_constraint + value_restriction = ":restrict => #{vr}" + end + + options = [ + ruby_role_name, + role_reference, + mandatory ? ":mandatory => true" : nil, + readings, + other_role_name, + value_restriction + ].compact + + line = " #{one_to_one ? "one_to_one" : "has_one" } #{options*', '} " + if other_method_name + line += " "*(48-line.length) if line.length < 48 + line += "\# See #{role_player.name.gsub(/ /,'')}.#{other_method_name}" + end puts line #puts " \# REVISIT: #{other_role_name} has values restricted to #{role.role_value_constraint}\n" if role.role_value_constraint end def object_type_reference object_type @@ -176,5 +195,7 @@ end end end end + +ActiveFacts::Registry.generator('ruby', ActiveFacts::Generate::RUBY)