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)