lib/activefacts/generator/doc/glossary.rb in activefacts-compositions-1.9.22 vs lib/activefacts/generator/doc/glossary.rb in activefacts-compositions-1.9.23
- old
+ new
@@ -11,23 +11,28 @@
module ActiveFacts
module Generators #:nodoc:
module Doc
class Glossary #:nodoc:
+ MM = ActiveFacts::Metamodel
+
# Options are comma or space separated:
- # * gen_bootstrap Generate bootstrap styled glossary html
def self.options
{
- gen_bootstrap: ['Boolean', "Generate bootstrap styled glossary html"],
}
end
-
+
+ def self.compatibility
+ [0, nil] # no composition is required
+ end
+
# Base class for generators of object-oriented class libraries for an ActiveFacts vocabulary.
- def initialize vocabulary, options = {}
- @vocabulary = vocabulary # REVISIT: This should be a Composition here
+ def initialize constellation, composition, options = {}
+ @constellation = constellation
+ @compositions = Array(composition)
+ @vocabulary = constellation.Vocabulary.values[0]
@options = options
- @gen_bootstrap = options.has_key?("gen_bootstrap")
end
def puts(*a)
@out.puts *a
end
@@ -39,125 +44,107 @@
def generate
@all_object_type =
@vocabulary.
all_object_type.
sort_by{|o| o.name.gsub(/ /,'').downcase}
-
+
+ "<html><head>" +
glossary_start +
+ "</head><body>" +
glossary_body +
- glossary_end
+ glossary_end +
+ "</body>"
end
def glossary_start
- if !@gen_bootstrap
- # puts "<link rel='stylesheet' href='css/orm2.css' media='screen' type='text/css'/>"
- css_file = "css/orm2.css"
-
- File.open(File.dirname(__FILE__)+css_file) do |f|
- "<style media='screen' type='text/css'>\n" +
- f.read +
- %Q{
- .glossary-facttype, .glossary-constraints { display: block; }\n
- .glossary-doc.hide-alternates .glossary-alternates { display: none; }\n
- .glossary-doc.hide-constraints .glossary-constraints { display: none; }\n
- .glossary-doc.hide-examples .glossary-example { display: none; }\n
- }.gsub(/^\s+/, '') +
- "</style>\n"
- end +
-
- %Q{
- <style media='print' type='text/css'>\n
- .keyword { color: #0000CC; font-style: italic; display: inline; }\n
- .vocabulary, .object_type { color: #8A0092; font-weight: bold; }\n
- .copula { color: #0E5400; }\n
- .value { color: #FF990E; display: inline; }\n
- .glossary-toc { display: none; }\n
- .glossary-facttype, .glossary-reading { display: inline; }\n
- </style>\n
- }.gsub(/^\s+/, '')
- else
- ''
- end
+ # Inline the following CSS files:
+ {
+ all: ["reset.css", "treetable.css"],
+ screen: ["orm2.css", "glossary.css"],
+ print: ["orm2-print.css", "glossary-print.css"]
+ }.
+ flat_map do |media, css_files|
+ css_files.map do |css_file|
+ File.open(filename = File.dirname(__FILE__)+"/css/"+css_file) do |f|
+ "<!-- #{css_file} -->\n"+
+ "<style media='#{media}' type='text/css'>\n#{f.read}</style>\n"
+ end
+ end
+ end*''.gsub(/^\s+/, '')
end
def glossary_body
- if @gen_bootstrap
- object_types_dump_toc()
- object_types_dump_def()
- else
- object_types_dump_def()
- object_types_dump_toc()
- end
+ div(
+ object_types_dump_toc +
+ object_types_dump_def +
+ dump_compositions +
+ controls,
+ 'glossary'
+ )
end
-
+
def glossary_end
- if !@gen_bootstrap
- %Q{
- <script type="text/javascript">
- function toggle_class(e, c) {
- if (!e) return;
- var n = e.className;
- var i = n.indexOf(c);
- if (i == -1) {
- e.className = n+' '+c;
- } else {
- e.className = n.slice(0, i)+n.slice(i+c.length);
- }
- if (document.location.toString().indexOf('#') >= 0)
- document.location = document.location; // Re-scroll to the current fragment
- }
- function toggle_constraints() {
- toggle_class(document.getElementById('glossary-doc'), 'hide-constraints');
- }
- function toggle_alternates() {
- toggle_class(document.getElementById('glossary-doc'), 'hide-alternates');
- }
- function toggle_examples() {
- toggle_class(document.getElementById('glossary-doc'), 'hide-examples');
- }
- </script>
- }.gsub(/^\s+/, '')
- else
- ''
- end
+ %Q{
+ <script type="text/javascript">
+ function toggle_class(e, c) {
+ if (!e) return;
+ var n = e.className;
+ var i = n.indexOf(c);
+ if (i == -1) {
+ e.className = n+' '+c;
+ } else {
+ e.className = n.slice(0, i)+n.slice(i+c.length);
+ }
+ if (document.location.toString().indexOf('#') >= 0)
+ document.location = document.location; // Re-scroll to the current fragment
+ }
+ function toggle_facts() {
+ toggle_class(document.getElementById('glossary-doc'), 'hide-facts');
+ }
+ function toggle_constraints() {
+ toggle_class(document.getElementById('glossary-doc'), 'hide-constraints');
+ }
+ function toggle_alternates() {
+ toggle_class(document.getElementById('glossary-doc'), 'hide-alternates');
+ }
+ function toggle_examples() {
+ toggle_class(document.getElementById('glossary-doc'), 'hide-examples');
+ }
+ </script>
+ }.gsub(/^\s+/, '')
end
def object_types_dump_toc
- if @gen_bootstrap
- '<div class="col-md-3 glossary-sidebar">' + "\n"
- else
- '<div class="glossary-sidebar">' + "\n"
- end +
- '<h1 style="visibility: hidden">X</h1>' +"\n" +
- '<ol class="glossary-toc">' + "\n"
+ %Q{\n<div class="glossary-toc#{@compositions.size > 0 ? ' glossary-is-toc' : ' glossary-toc-right'}">\n} +
+ # Don't show schema name here '<h1 style="visibility: hidden">X</h1>' +"\n" +
+ '<ol class="glossary-toc-list">' + "\n" +
@all_object_type.
- reject do |o|
- o.name == '_ImplicitBooleanValueType' or
- o.kind_of?(ActiveFacts::Metamodel::ValueType) && o.all_role.size == 0 or
- o.kind_of?(ActiveFacts::Metamodel::TypeInheritance)
- end.
- map do |o|
- "<li>#{termref(o.name)}</li>"
- end *"\n" + "\n" +
+ reject do |o|
+ o.name == '_ImplicitBooleanValueType' or
+ o.kind_of?(ActiveFacts::Metamodel::ValueType) && o.all_role.size == 0 or
+ o.kind_of?(ActiveFacts::Metamodel::TypeInheritance)
+ end.
+ map do |o|
+ "<li>#{termref(o.name)}</li>"
+ end*"\n" + "\n</div>\n\n"
+ end
+
+ def controls
%Q{
</ol>
<div class="glossary-controls">
+ <input type="button" onclick="toggle_facts()" value="Facts" class="glossary-toggle-facts">
<input type="button" onclick="toggle_constraints()" value="Constraints" class="glossary-toggle-constraint">
<input type="button" onclick="toggle_alternates()" value="Alternates" class="glossary-toggle-alternates">
<input type="button" onclick="toggle_examples()" value="Examples" class="glossary-toggle-examples">
</div>
- </div>
}
end
-
+
def object_types_dump_def
- if @gen_bootstrap
- '<div class="col-md-5 glossary-doc hide-alternates hide-constraints" id="glossary-doc">' + "\n"
- else
- '<div class="glossary-doc hide-alternates hide-constraints" id="glossary-doc">' + "\n"
- end +
- '<h1>#{@vocabulary.name}</h1>' + "\n" +
+ %Q{<div class="glossary-doc #{@compositions.size > 0 ? 'glossary-is-toc' : 'glossary-toc-right'} hide-facts hide-alternates hide-constraints" id="glossary-doc">} + "\n" +
+ "<h1>#{@vocabulary.name}</h1>\n" +
"<dl>\n" +
@all_object_type.
map do |o|
case o
when ActiveFacts::Metamodel::TypeInheritance
@@ -169,15 +156,150 @@
objectified_fact_type_dump(o)
else
entity_type_dump(o)
end
end
- end +
+ end*"\n" +
"</dl>\n" +
"</div>\n"
end
+ # Each component has
+ # * a span for the title,
+ # * a tt-type if it's a value type
+ # * an tt-desc if it has an associated fact type
+ # * child nodes
+ def component c, klass = ''
+ name = c.name
+ title = span(name, 'term'+(c.is_mandatory ? ' mandatory' : ''))
+ desc = ''
+ type = ''
+
+ case c
+ when MM::Indicator
+ ft = c.role.fact_type
+ desc = div(div(expand_reading(ft.preferred_reading, false), 'glossary-reading'), 'tt-desc')
+ type = div(div('boolean', 'term'), 'tt-type')
+
+ when MM::Discriminator,
+ MM::Injection,
+ MM::ComputedValue,
+ MM::HashValue,
+ MM::SurrogateKey,
+ # MM::Scoping,
+ MM::ValidFrom # This should be an Injection
+ p c
+ debugger
+ print ''
+ # REVISIT
+
+ when MM::Absorption
+ ft = c.parent_role.fact_type
+ preferred_reading = ft.reading_preferably_starting_with_role(c.parent_role)
+ desc = div(div(expand_reading(preferred_reading, false), 'glossary-reading'), 'tt-desc')
+ if MM::ValueType === c.object_type
+ name = c.column_name*''
+ title = span(name, 'term'+(c.is_mandatory ? ' mandatory' : ''))
+ type = div(div(c.child_role.object_type.name, 'term'), 'tt-type')
+ #elsif c.all_member.size == 0
+ # title = span(name, 'term'+(c.is_mandatory ? ' mandatory' : ''))
+ #else
+ title = span(name, 'term'+(c.is_mandatory ? ' mandatory' : ''))
+ end
+ if MM::TypeInheritance === ft
+ title = "as a "+title
+ elsif c.full_absorption
+ title = "fully absorbing "+title
+ end
+ if to = (c.foreign_key && c.foreign_key.composite) or
+ (
+ composite_mappings = c.object_type.all_mapping.select{|m| m.composite} and
+ composite_mappings.size == 1 and # In a binary mapping, there aren't any ForeignKeys
+ to = composite_mappings[0].composite
+ )
+ title = element(title, {href: '#'+composite_anchor(to)}, 'a')
+ end
+ klass = klass+' tt-list' unless c.parent_role.is_unique
+
+ # when MM::ValueField ... Mapping works here
+ when MM::Mapping # A mapping that's not an absorption; usually a Composite
+ if MM::EntityType === (o = c.object_type)
+ if o.fact_type
+ objectified_reading = o.fact_type.preferred_reading
+ desc = div(
+ span('is where ', :keyword) + expand_reading(objectified_reading, false),
+ 'tt-desc'
+ )
+ else
+ desc = div(
+ span('is identified by ', :keyword) +
+ o.preferred_identifier_roles.map{|r| span(r.role_name || r.name, 'term') }*', ',
+ 'tt-desc'
+ )
+ end
+ else
+ desc = div('', 'tt-desc')
+ end
+
+ when MM::Indicator
+ desc = div(
+ expand_reading(c.role.fact_type.preferred_reading, false),
+ 'tt-desc'
+ )
+ else
+ # Add other special cases here
+ desc = div('', 'tt-desc')
+ end
+
+
+ div(
+ title +
+ type +
+ desc +
+ c.
+ all_member.
+ sort_by{|m| m.ordinal}.
+ map do |member|
+ component(member)
+ end*'',
+ 'tt-node'+klass
+ )+"\n"
+ end
+
+ def dump_compositions
+ return '' if @compositions.empty?
+
+ element(
+ @compositions.map do |c|
+ "\n"+
+ element(
+ element(element(c.compositor_name + ' Composition', {href: "#{'#'}#{c.compositor_name}-composition"}, 'a'), {}, 'h2') + "\n" +
+ element(dump_composition(c), {}, 'div'),
+ {id: "#{c.compositor_name}-composition"},
+ 'section'
+ )
+ end*'',
+ {class: 'tabs glossary-compositions'},
+ 'article'
+ )
+ end
+
+ def composite_anchor composite
+ "#{composite.composition.compositor_name}_#{composite.mapping.name.words.titlecase}"
+ end
+
+ def dump_composition c
+ c.all_composite_by_name.map do |composite|
+ composite.mapping.re_rank
+ element(
+ component(composite.mapping, ' tt-outer'),
+ {name: composite_anchor(composite)},
+ 'a'
+ )
+ end*" \n"
+ end
+
def element(text, attrs, tag = 'span')
"<#{tag}#{attrs.empty? ? '' : attrs.map{|k,v| " #{k}='#{v}'"}*''}>#{text}</#{tag}>"
end
def span(text, klass = nil)
@@ -196,45 +318,45 @@
element(text, klass ? {:class => klass} : {}, 'dl')
end
# A definition of a term
def termdef(name)
- element(name, {:name => name, :class => 'object_type'}, 'a')
+ element(name, {:name => name, :class=>:term}, 'a')
end
# A reference to a defined term (excluding role adjectives)
def termref(name, role_name = nil)
role_name ||= name
- element(role_name, {:href=>'#'+name, :class=>:object_type}, 'a')
+ element(role_name, {:href=>'#'+name, :class=>:term}, 'a')
end
# Text that should appear as part of a term (including role adjectives)
def term(name)
- element(name, :class=>:object_type)
+ element(name, :class=>:term)
end
def value_type_dump(o, include_alternate = true, include_facts = true, include_constraints = true)
return '' if o.all_role.size == 0 or # Skip value types that are only used as supertypes
o.name == '_ImplicitBooleanValueType'
-
+
defn_term =
' <dt>' +
"#{termdef(o.name)} " +
(if o.supertype
span('is written as ', :keyword) + termref(o.supertype.name)
else
- " (a fundamental data type)"
+ " (fundamental)"
end) +
"</dt>\n"
defn_detail =
" <dd>\n" +
value_sub_types(o) +
relevant_facts_and_constraints(o, include_alternate, include_facts, include_constraints) +
(include_facts ? values(o) : '') +
" </dd>\n"
-
+
defn_term + defn_detail
end
def value_sub_types(o)
o.
@@ -267,18 +389,18 @@
)
end * "\n" + "\n"
end
def relevant_facts_and_constraints(o, include_alternate = true, include_facts = true, include_constraints = true)
- o.
- all_role.
- map{|r| r.fact_type}.
- uniq.
- reject do |ft| ft.is_a?(ActiveFacts::Metamodel::LinkFactType) end.
- map { |ft| [ft, " #{fact_type_with_constraints(ft, include_alternate, o, include_constraints)}"] }.
- sort_by{|ft, text| [ ft.is_a?(ActiveFacts::Metamodel::TypeInheritance) ? 0 : 1, text]}.
- map{|ft, text| text} * "\n"
+ o.
+ all_role.
+ map{|r| r.fact_type}.
+ uniq.
+ reject do |ft| ft.is_a?(ActiveFacts::Metamodel::LinkFactType) end.
+ map { |ft| [ft, " #{fact_type_with_constraints(ft, include_alternate, o, include_constraints)}"] }.
+ sort_by{|ft, text| [ ft.is_a?(ActiveFacts::Metamodel::TypeInheritance) ? 0 : 1, text]}.
+ map{|ft, text| text} * "\n"
end
def role_ref(rr, freq_con, l_adj, name, t_adj, role_name_def, literal)
term_parts = [l_adj, termref(name), t_adj].compact
[
@@ -297,11 +419,11 @@
span("(as #{ termref(rr.role.object_type.name, $1) })", 'keyword')
}
end
role_ref rr, freq_con, l_adj, name, t_adj, role_name_def, literal
end,
- {:class => 'copula'}
+ {:class => 'reading'}
)
end
def fact_type_block(ft, include_alternates = true, wrt = nil, include_rolenames = true)
div(fact_type(ft, include_alternates, wrt, include_rolenames), 'glossary-facttype')
@@ -334,12 +456,13 @@
end
def fact_type_with_constraints(ft, include_alternates = true, wrt = nil, include_constraints = true)
if ft.entity_type
div(
- div(termref(ft.entity_type.name) + span(' is where ', 'keyword')) +
- div(fact_type(ft, include_alternates, wrt)),
+ (ft.entity_type == wrt ? '' : termref(ft.entity_type.name)) +
+ span(' is where ', 'keyword') +
+ fact_type(ft, include_alternates, wrt),
'glossary-objectification'
)
else
fact_type_block(ft, include_alternates, wrt)
end +
@@ -365,72 +488,72 @@
}
next '' unless reading
div(
element(
reading.expand_with_final_presence_constraint { |*a| role_ref(*a) },
- {:class => 'copula'}
+ {:class => 'reading'}
),
'glossary-constraint'
) + "\n"
end.compact * ''
end
def objectified_fact_type_dump(o, include_alternate = true, include_facts = true, include_constraints = true)
defn_term =
" <dt>" +
"#{termdef(o.name)}" +
- # " (#{span('in which', 'keyword')} #{fact_type(o.fact_type, false, nil, nil)})" +
+ " (objectification#{o.supertypes.size > 0 ? ', subtype' : ''})" +
+ # Don't display OFT inline " (#{span('in which', 'keyword')} #{fact_type(o.fact_type, false, o, nil)})" +
"</dt>\n"
# REVISIT: Handle separate identification
defn_detail =
- " <dd>\n" +
- fact_type_with_constraints(o.fact_type, include_alternate, nil, include_constraints) + "\n" +
+ " <dd>" +
+ fact_type_with_constraints(o.fact_type, include_alternate, o, include_constraints) + "\n" +
o.fact_type.all_role_in_order.map do |r|
n = r.object_type.name
div("#{termref(o.name)} involves #{span('one', 'keyword')} #{termref(r.role_name || n, n)}", "glossary-facttype")
end * "\n" + "\n" +
relevant_facts_and_constraints(o, include_alternate, include_facts, include_constraints) + "\n" +
- " </dd>"
+ " </dd>\n"
defn_term + defn_detail
end
def entity_type_dump(o, include_alternate = true, include_facts = true, include_constraints = true)
pi = o.preferred_identifier
supers = o.supertypes
- if (supers.size > 0) # Ignore identification by a supertype:
- pi = nil if pi && pi.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) }
- end
+ pi = nil if pi && o.identifying_supertype
defn_term =
" <dt>" +
"#{termdef(o.name)} " +
- "</dt>\n"
-
- defn_detail =
- " <dd>" +
- (supers.size > 0 ? "#{span('is a kind of', 'keyword')} #{supers.map{|s| termref(s.name)}*', '}\n" : '') +
if pi
"#{span('is identified by', 'keyword')} " +
pi.role_sequence.all_role_ref_in_order.map do |rr|
- termref(
- rr.role.object_type.name,
- [ rr.leading_adjective,
- rr.role.role_name || rr.role.object_type.name,
- rr.trailing_adjective
- ].compact * '-'
+ preferred_reading = rr.role.fact_type.preferred_reading
+ preferred_role_ref = preferred_reading.role_sequence.all_role_ref.detect{|rrp| rrp.role == rr.role}
+ term(
+ [ preferred_role_ref.leading_adjective,
+ termref(rr.role.object_type.name, preferred_role_ref.role.role_name),
+ preferred_role_ref.trailing_adjective
+ ].compact*'-'
)
end * ", " + "\n"
else
- ''
+ ' (subtype)'
end +
+ "</dt>\n"
+
+ defn_detail =
+ " <dd>\n" +
+ (supers.size > 0 ? "#{span('is a kind of', 'keyword')} #{supers.map{|s| termref(s.name)}*', '}\n" : '') +
relevant_facts_and_constraints(o, include_alternate, include_facts, include_constraints) +
(include_facts ? entities(o) : '') +
- " </dd>\n"
-
+ "\n </dd>"
+
defn_term + defn_detail
end
def entities(o)
return '' if o.preferred_identifier.role_sequence.all_role_ref.size > 1 # REVISIT: Composite identification
@@ -464,8 +587,9 @@
)
end * "\n" + "\n"
end
end
end
+ publish_generator Doc::Glossary, "Glossary generator"
end
end