activefacts-compositions 1.9.1 → 1.9.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c0c06e12306cedaf28c2c97bb4402eefcca710b1
4
- data.tar.gz: 3e04e43481658439e3ede1b0617e7894b3396f6b
3
+ metadata.gz: bad26d18580fa095acc7cbb4a2722694f0020c30
4
+ data.tar.gz: 45c9fc0cf6516095c7794bd7fb291ce33c80b074
5
5
  SHA512:
6
- metadata.gz: bb18efed6ff85d453708918973589714f30d39e7e65132337d64919146e21be7a28a6e79b9769f4ff94c45dfed9fc7b9abe22a0999bdd76044666ea7151ee348
7
- data.tar.gz: f32477f6a63fec1b57c7d387f4ef9a61371e1ff0944105e47ceff312cddd8099fc9563e2cd50b66c762279c0885e7cba19a09441438cc9e6abdac6325a2e0155
6
+ metadata.gz: 76fafc569a0516de38ddb19e604c243ec7b87318823fffac3bd3b8b84ec491e131d4429dae139944322a2882574e2c6d9693fad176fa9962dcf2f5495851f13b
7
+ data.tar.gz: ca70f4978bffffea9737812c3199503a81242809f0f0a27674be0c769b96d82aef6937a7cbd0213ac50ac971684ee2ec476e9c6c517729de1d92a109b45bd782
data/Gemfile CHANGED
@@ -2,10 +2,9 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- if ENV['PWD'] =~ %r{\A#{ENV['HOME']}/work}
5
+ if ENV['PWD'] =~ %r{\A#{ENV['HOME']}/work}i
6
6
  $stderr.puts "Using work area gems for #{File.basename(File.dirname(__FILE__))} from activefacts-compositions"
7
- gem 'activefacts-api', path: '/Users/cjh/work/activefacts/api'
8
- gem 'activefacts-metamodel', path: '/Users/cjh/work/activefacts/metamodel'
9
- gem 'activefacts-cql', path: '/Users/cjh/work/activefacts/cql'
10
- # gem 'activefacts-metamodel', git: 'git://github.com/cjheath/activefacts-metamodel.git'
7
+ gem 'activefacts-api', path: '../api'
8
+ gem 'activefacts-metamodel', path: '../metamodel'
9
+ gem 'activefacts-cql', path: '../cql'
11
10
  end
data/README.md CHANGED
@@ -1,12 +1,17 @@
1
1
  # ActiveFacts::Compositions
2
2
 
3
- Create and represent composite schemas, schema transforms and data transforms over a fact-based model.
3
+ Fact-based schemas are always in highly normalised or *elementary* form.
4
+ Most other schemas are composite (object-oriented, relational, warehousing, analytical, messaging, APIs, etc).
5
+ This gem provides the framework for *Compositions*, which are representations of the two-way mapping between an elementary schema and a composite schema.
6
+ As such, it supports any-to-any mappings between different composite forms.
7
+
8
+ It also provides automated generators for some types of composite schemas, especially relational and Data Vault schemas.
4
9
 
5
10
  This gem works with the Fact Modeling tools as part of ActiveFacts.
6
11
 
7
12
  ## Installation
8
13
 
9
- Install via the activefacts gem bundle, or add this line to your application's Gemfile:
14
+ Install as part of activefacts, just "gem install" directly, or add this line to your application's Gemfile:
10
15
 
11
16
  ```ruby
12
17
  gem 'activefacts-compositions'
@@ -16,16 +21,17 @@ And then execute:
16
21
 
17
22
  $ bundle
18
23
 
19
- Or install it yourself as:
20
-
21
- $ gem install activefacts-compositions
22
-
23
24
  ## Usage
24
25
 
25
- This gem adds schema manipulation tools (mappers, composers, transformations, generators) to the generator framework for activefacts. Refer to the afgen command-line tool for help:
26
+ This gem adds schema manipulation tools (mappers, composers, transformations) to the generator framework for *activefacts*.
27
+ Refer to the afgen command-line tool for help:
26
28
 
27
29
  $ afgen --help
28
30
 
31
+ A stand-alone relational generator program is provided, mostly for exploratory purposes; use tracing to see what it is doing, e.g.:
32
+
33
+ $ TRACE=relational bin/schema_compositor --surrogate spec/relational/CompanyDirectorEmployee.cql
34
+
29
35
  ## Development
30
36
 
31
37
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests.
@@ -36,7 +42,6 @@ To install this gem onto your local machine, run `bundle exec rake install`.
36
42
 
37
43
  Bug reports and pull requests are welcome on GitHub at https://github.com/cjheath/activefacts-compositions.
38
44
 
39
-
40
45
  ## License
41
46
 
42
47
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -4,3 +4,20 @@ require "rspec/core/rake_task"
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
6
  task :default => :spec
7
+
8
+ desc "Bump gem version patch number"
9
+ task :bump do
10
+ path = File.expand_path('../lib/activefacts/compositions/version.rb', __FILE__)
11
+ lines = File.open(path) do |fp| fp.readlines; end
12
+ File.open(path, "w") do |fp|
13
+ fp.write(
14
+ lines.map do |line|
15
+ line.gsub(/(VERSION *= *"[0-9.]*\.)([0-9]+)"\n/) do
16
+ version = "#{$1}#{$2.to_i+1}"
17
+ puts "Version bumped to #{version}\""
18
+ version+"\"\n"
19
+ end
20
+ end*''
21
+ )
22
+ end
23
+ end
@@ -23,7 +23,10 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
24
  spec.add_development_dependency "rspec", "~> 3.3"
25
25
 
26
- spec.add_runtime_dependency("activefacts-metamodel", ">= 1.9", "~> 1.9.0")
27
- spec.add_development_dependency "activefacts", "~> 1.8", "~> 1.8.0"
28
- spec.add_development_dependency "activefacts-cql", "~> 1.8", "~> 1.8.0"
26
+ spec.add_runtime_dependency("activefacts-api", "~> 1", ">= 1.9.2")
27
+ spec.add_runtime_dependency("activefacts-metamodel", "~> 1", ">= 1.9.1")
28
+ spec.add_runtime_dependency "tracing", "~> 2", ">= 2.0.5"
29
+
30
+ spec.add_development_dependency "activefacts", "~> 1", ">= 1.8"
31
+ spec.add_development_dependency "activefacts-cql", "~> 1", ">= 1.8"
29
32
  end
@@ -11,12 +11,19 @@ $:.unshift File.dirname(File.expand_path(__FILE__))+"/../lib"
11
11
  require 'activefacts/metamodel'
12
12
  require 'activefacts/compositions/binary'
13
13
  require 'activefacts/compositions/relational'
14
+ require 'activefacts/compositions/validator'
14
15
 
15
- arg = ARGV.shift
16
+ options = {}
17
+ while arg = ARGV.shift and arg =~ /^-/
18
+ option, value = arg.split(/=/, 2)
19
+ options[option.sub(/^-*/,'')] = value =~ /,/ ? value.split(',') : (value || true)
20
+ end
21
+
22
+ validate = options.delete('validate')
16
23
 
17
24
  # Load the file type input method
18
25
  if arg
19
- arg, *options = *arg.split(/=/)
26
+ arg, input_options = *arg.split(/=/, 2)
20
27
  extension = arg.sub(/\A.*\./,'').downcase
21
28
  input_handler = "activefacts/input/#{extension}"
22
29
  require input_handler
@@ -29,7 +36,7 @@ end
29
36
  # Read the input file:
30
37
  begin
31
38
  if input_klass
32
- vocabulary = input_klass.readfile(arg, *options)
39
+ vocabulary = input_klass.readfile(arg, *input_options)
33
40
  else
34
41
  vocabulary = true
35
42
  end
@@ -38,8 +45,12 @@ begin
38
45
 
39
46
  vocabulary.finalise unless vocabulary == true
40
47
 
41
- compositor = ActiveFacts::Compositions::Relational.new(vocabulary.constellation, "test")
48
+ compositor = ActiveFacts::Compositions::Relational.new(vocabulary.constellation, "test", options)
42
49
  compositor.generate
50
+ trace.enable 'composition_validator'
51
+ compositor.validate do |component, problem|
52
+ trace :composition_validator, "!!PROBLEM!! #{component.inspect}: #{problem}"
53
+ end if validate
43
54
 
44
55
  rescue => e
45
56
  $stderr.puts "#{e.message}"
@@ -13,14 +13,14 @@ module ActiveFacts
13
13
  def generate
14
14
  super
15
15
 
16
- trace :binary_, "Constructing Binary Composition" do
16
+ trace :binary!, "Constructing Binary Composition" do
17
17
  @binary_mappings.keys.sort_by(&:name).each do |object_type|
18
18
  mapping = @binary_mappings[object_type]
19
19
  mapping.re_rank
20
20
  end
21
21
  end
22
22
 
23
- trace :binary_, "Full binary composition" do
23
+ trace :binary!, "Full binary composition" do
24
24
  @binary_mappings.keys.sort_by(&:name).each do |object_type|
25
25
  mapping = @binary_mappings[object_type]
26
26
  mapping.show_trace
@@ -16,6 +16,8 @@ require "activefacts/metamodel"
16
16
  module ActiveFacts
17
17
  module Compositions
18
18
  class Compositor
19
+ attr_reader :options, :name
20
+
19
21
  def initialize constellation, name, options = {}
20
22
  @constellation = constellation
21
23
  @name = name
@@ -32,10 +34,17 @@ module ActiveFacts
32
34
  end
33
35
 
34
36
  @composition = @constellation.Composition(:new, :name => @name)
37
+ preload_preferred_identifiers
35
38
  populate_references
36
39
  end
37
40
 
38
41
  private
42
+ # Preferred identifiers are cached, but the process produces trace output
43
+ # that appears in the "tutti" mode used in testing. This precludes that.
44
+ def preload_preferred_identifiers
45
+ @constellation.EntityType.map{|k, et| et.preferred_identifier }
46
+ end
47
+
39
48
  def populate_reference object_type, role
40
49
  parent = @binary_mappings[role.object_type]
41
50
 
@@ -44,12 +53,12 @@ module ActiveFacts
44
53
  counterpart = role.counterpart
45
54
  rt = role_type(counterpart)
46
55
  if rt == :many_many
47
- raise "Can't absorb many-to-many (until we absorb derived fact types, or don't require explicit objectification)"
56
+ raise "Fact type must be objectified: #{role.fact_type.default_reading}"
48
57
  end
49
58
 
50
59
  a = @constellation.Absorption(
51
60
  :new,
52
- name: counterpart.name,
61
+ name: role_name(counterpart),
53
62
  parent: parent,
54
63
  object_type: counterpart.object_type,
55
64
  parent_role: role,
@@ -59,9 +68,9 @@ module ActiveFacts
59
68
  if r = @component_by_fact[role.fact_type]
60
69
  # Second occurrence of this fact type, set the direction:
61
70
  if a.is_preferred_direction
62
- a.absorption = r
63
- else # Set this as the reverse absorption
64
71
  a.reverse_absorption = r
72
+ else # Set this as the reverse absorption
73
+ a.forward_absorption = r
65
74
  end
66
75
  else
67
76
  # First occurrence of this fact type
@@ -95,7 +104,8 @@ module ActiveFacts
95
104
  @binary_mappings[object_type] # Ensure we create the top Mapping even if it has no references
96
105
 
97
106
  object_type.all_role.each do |role|
98
- next if role.mirror_role_as_base_role # Exclude base roles, just use link fact types
107
+ # Exclude base roles in objectified fact types (unless unary); just use link fact types
108
+ next if role.fact_type.entity_type && role.fact_type.all_role.size != 1
99
109
  next if role.variable_as_projection # REVISIT: Continue to ignore roles in derived fact types?
100
110
  populate_reference object_type, role
101
111
  end
@@ -112,6 +122,13 @@ module ActiveFacts
112
122
  end
113
123
  end
114
124
 
125
+ def role_name role
126
+ # if role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) && role == role.fact_type.subtype_role
127
+ # return "Is "+role.object_type.name
128
+ # end
129
+ String::Words.new(role.base_role.preferred_reference.role_name(nil)).capwords*' '
130
+ end
131
+
115
132
  def role_type role
116
133
  fact_type = role.fact_type
117
134
  if fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)