activefacts-api 0.9.7 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc17ae7a132478e2e4b591e19adf35d79627d70b
4
+ data.tar.gz: b6b63e83981a4ec466aa128b94fb7cfbf1370d0e
5
+ SHA512:
6
+ metadata.gz: 916183df4492dab5a94c172d85f58b7f4a04f8407eb9decc301b07c8f137a5c6b3bfd4c80ce4f4d7b98e5ba9fe26d0483dd3a71b768159701b63d0c07b3a0b1e
7
+ data.tar.gz: 14858f846fe7c1fba970cd1b2cd6f890d21ae5247ce2107d73c49e75d919cf011814bd724e8b90ace9fdd524b262a3c83538b242137452d13eb8c0f454758323
data/.travis.yml CHANGED
@@ -3,6 +3,7 @@ rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
5
  - 1.9.3
6
+ - 2.0.0
6
7
  - jruby-18mode
7
8
  - jruby-19mode
8
9
  - rbx-18mode
data/Gemfile CHANGED
@@ -1,13 +1,15 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rake', :group => [:development, :test]
3
+ gem 'rake', '>=10.1', :group => [:development, :test]
4
4
  gem 'rbtree-pure'
5
5
 
6
6
  group :development do
7
7
  gem 'jeweler'
8
8
  gem 'rspec', '~>2.6.0'
9
9
  gem 'ruby-debug', :platforms => [:mri_18]
10
- gem 'debugger', :platforms => [:mri_19]
10
+ gem 'debugger', :platforms => [:mri_19,
11
+ (['1.8.7', '1.9.2'].include?(RUBY_VERSION) || RUBY_PLATFORM == 'java') ? nil : :mri_20
12
+ ].compact
11
13
  gem 'pry', :platforms => [:jruby, :rbx]
12
14
  end
13
15
 
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ end
42
42
 
43
43
  namespace :spec do
44
44
  namespace :rubies do
45
- SUPPORTED_RUBIES = %w{ 1.8.7 1.9.2 1.9.3 jruby-1.7.0 rbx }
45
+ SUPPORTED_RUBIES = %w{ 1.9.2 1.9.3 2.0.0 jruby-1.7.0 }
46
46
 
47
47
  desc "Run Rspec tests on all supported rubies"
48
48
  task :all_tasks => [:install_gems, :exec]
@@ -56,6 +56,19 @@ namespace :spec do
56
56
  task :exec do
57
57
  sh %{ rvm #{SUPPORTED_RUBIES.join(',')} exec bundle exec rake spec }
58
58
  end
59
+
60
+ SUPPORTED_RUBIES.each do |ruby|
61
+ desc "Run `bundle install` on #{ruby}"
62
+ task :"install_gems_#{ruby}" do
63
+ sh %{ rvm #{ruby} exec bundle install }
64
+ end
65
+
66
+ desc "Run `bundle exec rake` on #{ruby}"
67
+ task :"exec_#{ruby}" do
68
+ sh %{ rvm #{ruby} exec bundle exec rake spec }
69
+ end
70
+ end
71
+
59
72
  end
60
73
  end
61
74
 
@@ -81,3 +94,8 @@ Rake::RDocTask.new do |rdoc|
81
94
  rdoc.rdoc_files.include('README*')
82
95
  rdoc.rdoc_files.include('lib/**/*.rb')
83
96
  end
97
+
98
+ task :wait do
99
+ print "Waiting for you to hit Enter"
100
+ $stdin.gets
101
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.7
1
+ 0.9.8
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "activefacts-api"
8
- s.version = "0.9.7"
8
+ s.version = "0.9.8"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Clifford Heath"]
12
- s.date = "2013-01-29"
12
+ s.date = "2013-11-13"
13
13
  s.description = "\nThe ActiveFacts API is a Ruby DSL for managing constellations of elementary facts.\nEach fact is either existential (a value or an entity), characteristic (boolean) or\nbinary relational (A rel B). Relational facts are consistently co-referenced, so you\ncan traverse them efficiently in any direction. Each constellation maintains constraints\nover the fact population.\n"
14
14
  s.email = "clifford.heath@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -68,15 +68,15 @@ Gem::Specification.new do |s|
68
68
  s.homepage = "http://github.com/cjheath/activefacts-api"
69
69
  s.licenses = ["MIT"]
70
70
  s.require_paths = ["lib"]
71
- s.rubygems_version = "1.8.24"
71
+ s.rubygems_version = "2.0.5"
72
72
  s.summary = "A fact-based data model DSL and API"
73
73
 
74
74
  if s.respond_to? :specification_version then
75
- s.specification_version = 3
75
+ s.specification_version = 4
76
76
 
77
77
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
78
78
  s.add_runtime_dependency(%q<rbtree-pure>, [">= 0"])
79
- s.add_development_dependency(%q<rake>, [">= 0"])
79
+ s.add_development_dependency(%q<rake>, [">= 10.1"])
80
80
  s.add_development_dependency(%q<jeweler>, [">= 0"])
81
81
  s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
82
82
  s.add_development_dependency(%q<ruby-debug>, [">= 0"])
@@ -88,7 +88,7 @@ Gem::Specification.new do |s|
88
88
  s.add_development_dependency(%q<rdoc>, [">= 2.4.2"])
89
89
  else
90
90
  s.add_dependency(%q<rbtree-pure>, [">= 0"])
91
- s.add_dependency(%q<rake>, [">= 0"])
91
+ s.add_dependency(%q<rake>, [">= 10.1"])
92
92
  s.add_dependency(%q<jeweler>, [">= 0"])
93
93
  s.add_dependency(%q<rspec>, ["~> 2.6.0"])
94
94
  s.add_dependency(%q<ruby-debug>, [">= 0"])
@@ -101,7 +101,7 @@ Gem::Specification.new do |s|
101
101
  end
102
102
  else
103
103
  s.add_dependency(%q<rbtree-pure>, [">= 0"])
104
- s.add_dependency(%q<rake>, [">= 0"])
104
+ s.add_dependency(%q<rake>, [">= 10.1"])
105
105
  s.add_dependency(%q<jeweler>, [">= 0"])
106
106
  s.add_dependency(%q<rspec>, ["~> 2.6.0"])
107
107
  s.add_dependency(%q<ruby-debug>, [">= 0"])
@@ -139,8 +139,15 @@ module ActiveFacts
139
139
  # This method removes the given instance from this constellation's indexes
140
140
  # It must be called before the identifying roles get deleted or nullified.
141
141
  def deindex_instance(instance) #:nodoc:
142
+ last_irns = nil
143
+ last_irvs = instance
142
144
  ([instance.class]+instance.class.supertypes_transitive).each do |klass|
143
- instances[klass].delete(instance.identifying_role_values(klass))
145
+ if instance.is_a?(Entity) and last_irns != (n = klass.identifying_role_names)
146
+ # Build new identifying_role_values only when the identifying_role_names change:
147
+ last_irvs = instance.identifying_role_values(klass)
148
+ last_irns = n
149
+ end
150
+ instances[klass].delete(last_irvs)
144
151
  end
145
152
  # REVISIT: Need to nullify all the roles this object plays.
146
153
  # If mandatory on the counterpart side, this may/must propagate the delete (without mutual recursion!)
@@ -45,7 +45,9 @@ module ActiveFacts
45
45
  end
46
46
 
47
47
  begin
48
+ @constellation.send(:instance_variable_set, :@suspend_duplicate_key_check, true)
48
49
  send(role.setter, value)
50
+ @constellation.send(:instance_variable_set, :@suspend_duplicate_key_check, false)
49
51
  # rescue NoMethodError => e
50
52
  # raise settable_roles_exception(e, role_name)
51
53
  end
@@ -99,8 +101,8 @@ module ActiveFacts
99
101
  # When used as a hash key, the hash key of this entity instance is calculated
100
102
  # by hashing the values of its identifying roles
101
103
  def hash
102
- self.class.identifying_role_names.map{|role_name|
103
- instance_variable_get("@#{role_name}")
104
+ self.class.identifying_roles.map{|role|
105
+ instance_variable_get(role.variable)
104
106
  }.inject(0) { |h,v|
105
107
  h ^= v.hash
106
108
  h
@@ -391,6 +393,12 @@ module ActiveFacts
391
393
  # which is a list of roles it plays. The identification scheme may be
392
394
  # inherited from a superclass.
393
395
  def identified_by(*args) #:nodoc:
396
+ options = (args[-1].is_a?(Hash) ? args.pop : {})
397
+ options.each do |key, value|
398
+ raise UnrecognisedOptionsException.new('EntityType', basename, key) unless respond_to?(key)
399
+ send(key, value)
400
+ end
401
+
394
402
  raise MissingIdentificationException.new(self) unless args.size > 0
395
403
 
396
404
  # Catch the case where we state the same identification as our superclass:
@@ -426,7 +434,7 @@ module ActiveFacts
426
434
 
427
435
  def other.new_instance constellation, *args
428
436
  instance = allocate
429
- instance.instance_variable_set("@constellation", constellation)
437
+ instance.instance_variable_set(@@constellation_variable_name ||= "@constellation", constellation)
430
438
  instance.send(:initialize, *args)
431
439
  instance
432
440
  end
@@ -33,7 +33,7 @@ module ActiveFacts
33
33
  if is_single
34
34
  "#{object_type} has a single identifying role '#{role}' which is has_one, but must be one_to_one"
35
35
  else
36
- raise "#{object_type} has an identifying role '#{role}' which is one_to_one, but must be has_one"
36
+ "#{object_type} has an identifying role '#{role}' which is one_to_one, but must be has_one"
37
37
  end
38
38
  super msg
39
39
  end
@@ -47,7 +47,7 @@ module ActiveFacts
47
47
 
48
48
  class InvalidObjectType < SchemaException
49
49
  def initialize vocabulary, klass, reason
50
- raise "A constellation over #{vocabulary.name} cannot index instances of #{klass} because it #{reason}"
50
+ super "A constellation over #{vocabulary.name} cannot index instances of #{klass} because it #{reason}"
51
51
  end
52
52
  end
53
53
 
@@ -59,7 +59,7 @@ module ActiveFacts
59
59
 
60
60
  class UnrecognisedOptionsException < SchemaException
61
61
  def initialize declaration, instance, option_names
62
- raise "Unrecognised options on declaration of #{declaration} #{instance}: #{option_names.inspect}"
62
+ super "Unrecognised options on declaration of #{declaration} #{instance}: #{option_names.inspect}"
63
63
  end
64
64
  end
65
65
 
@@ -4,7 +4,11 @@ require 'securerandom'
4
4
  unless defined? SecureRandom.uuid
5
5
  # I think this only applies to 1.8.6 (and JRuby/Rubinius in 1.8 mode) now:
6
6
  def SecureRandom.uuid
7
- hex(16).sub(/(........)(....)(....)(....)(............)/,'\1-\2-\3-\4-\5')
7
+ hex(16).
8
+ sub(
9
+ @@format_pattern ||= /(........)(....)(....)(....)(............)/,
10
+ @@format_string ||= '\1-\2-\3-\4-\5'
11
+ )
8
12
  end
9
13
  end
10
14
 
@@ -4,8 +4,6 @@
4
4
  #
5
5
  # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
6
  #
7
- # Instance methods are extended into all instances, whether of value or entity types.
8
- #
9
7
  module ActiveFacts
10
8
  module API
11
9
  # Every Instance of a ObjectType (A Value type or an Entity type) includes the methods of this module:
@@ -36,6 +34,7 @@ module ActiveFacts
36
34
  # We need to check each superclass that has a different identification pattern
37
35
  def check_identification_change_legality(role, value)
38
36
  return unless @constellation && role.is_identifying
37
+ return if @constellation.send(:instance_variable_get, :@suspend_duplicate_key_check)
39
38
 
40
39
  klasses = [self.class] + self.class.supertypes_transitive
41
40
  last_identity = nil
@@ -83,6 +82,15 @@ module ActiveFacts
83
82
  # Now, for all roles (from this class and all supertypes), assign nil to all functional roles
84
83
  # The counterpart roles get cleared automatically.
85
84
  klasses = [self.class]+self.class.supertypes_transitive
85
+
86
+ irvks = {} # identifying_role_values by class
87
+ klasses.each do |klass|
88
+ if !irvks[klass] and klass.roles.detect{|_, role| role.counterpart and !role.counterpart.unique and send(role.getter) }
89
+ # We will need the identifying_role_values for this role's object_type
90
+ irvks[klass] = identifying_role_values(klass)
91
+ end
92
+ end
93
+
86
94
  klasses.each do |klass|
87
95
  klass.roles.each do |role_name, role|
88
96
  next if role.unary?
@@ -94,13 +102,15 @@ module ActiveFacts
94
102
  i = send(role.getter)
95
103
  next unless i
96
104
  if counterpart.is_identifying && counterpart.mandatory
105
+ # We play a mandatory identifying role in i; so retract that (it'll clear our instance variable)
97
106
  i.retract
98
107
  else
99
108
  if (counterpart.unique)
100
109
  # REVISIT: This will incorrectly fail to propagate a key change for a non-mandatory role
101
110
  i.send(counterpart.setter, nil, false)
102
111
  else
103
- i.send(role.counterpart.getter).update(self, nil)
112
+ rv = i.send(role.counterpart.getter)
113
+ rv.delete_instance(self, irvks[role.object_type])
104
114
  end
105
115
  end
106
116
  instance_variable_set(role.variable, nil)
@@ -126,10 +136,6 @@ module ActiveFacts
126
136
  include ObjectType
127
137
  # Add Instance class methods here
128
138
  end
129
-
130
- def self.included other #:nodoc:
131
- other.send :extend, ClassMethods
132
- end
133
139
  end
134
140
  end
135
141
  end
@@ -56,6 +56,7 @@ module ActiveFacts
56
56
  # arguments (where ObjectType is the object_type name you're interested in)
57
57
  #
58
58
  class InstanceIndex
59
+ attr_reader :sort
59
60
 
60
61
  # Should be in module ForwardableWithArityChecking
61
62
  def self.def_single_delegator(accessor, method, *expected_arities)
@@ -18,7 +18,7 @@ module ActiveFacts
18
18
 
19
19
  # Each ObjectType maintains a list of the Roles it plays:
20
20
  def roles(role_name = nil)
21
- unless instance_variable_defined? "@roles" # Avoid "instance variable not defined" warning from ||=
21
+ unless instance_variable_defined?(@@roles_name ||= "@roles") # Avoid "instance variable not defined" warning from ||=
22
22
  @roles = RoleCollection.new
23
23
  end
24
24
  case role_name
@@ -58,7 +58,8 @@ module ActiveFacts
58
58
  # Define a unary fact type attached to this object_type; in essence, a boolean attribute.
59
59
  #
60
60
  # Example: maybe :is_ceo
61
- def maybe(role_name)
61
+ def maybe(role_name, options = {})
62
+ raise UnrecognisedOptionsException.new("role", role_name, options.keys) unless options.empty?
62
63
  realise_role(roles[role_name] = Role.new(self, TrueClass, role_name))
63
64
  end
64
65
 
@@ -319,14 +320,16 @@ module ActiveFacts
319
320
  impacts = analyse_impacts(role)
320
321
  end
321
322
 
323
+ old_key = identifying_role_values(role.object_type) if old && mutual_propagation
324
+
322
325
  instance_variable_set(role_var, value)
323
326
 
324
327
  # Remove "self" from the old counterpart:
325
- old.send(getter = role.counterpart.getter).update(self, nil) if old && mutual_propagation
328
+ old.send(getter = role.counterpart.getter).delete_instance(self, old_key) if old_key
326
329
 
327
330
  @constellation.when_admitted do
328
331
  # Add "self" into the counterpart
329
- value.send(getter ||= role.counterpart.getter).update(old, self) if value
332
+ value.send(getter ||= role.counterpart.getter).add_instance(self, identifying_role_values(role.object_type)) if value
330
333
 
331
334
  apply_impacts(impacts) if impacts # Propagate dependent key changes
332
335
  end
@@ -350,7 +353,6 @@ module ActiveFacts
350
353
  # :class => the related class (Class object or Symbol). Not allowed if role_name was a class.
351
354
  # :mandatory => true. There must be a related object for this object to be valid.
352
355
  # :counterpart => Symbol/String. The name of the counterpart role. Will be to_s.snakecase'd and maybe augmented with "all_" and/or "_as_<role_name>"
353
- # :reading => "forward/reverse". Forward and reverse readings. Must include MARKERS for the player names. May include adjectives. REVISIT: define MARKERS!
354
356
  # LATER:
355
357
  # :order => :local_role OR lambda{} (for sort_by)
356
358
  # :restrict => Range or Array of Range/value or respond_to?(include?)
@@ -413,11 +415,6 @@ module ActiveFacts
413
415
 
414
416
  related_role_name = related_role_name.to_s if related_role_name = options.delete(:counterpart)
415
417
 
416
- reading = options.delete(:reading) # REVISIT: Implement verbalisation
417
- role_value_constraint = options.delete(:restrict) # REVISIT: Implement role value constraints
418
-
419
- additional_role_options options
420
-
421
418
  raise UnrecognisedOptionsException.new("role", role_name, options.keys) unless options.empty?
422
419
 
423
420
  # If you have a role "supervisor" and a sub-class "Supervisor", this'll bitch.
@@ -447,10 +444,6 @@ module ActiveFacts
447
444
  ]
448
445
  end
449
446
 
450
- def additional_role_options options
451
- # This is a hook for extensions to override. Any extension options should be deleted from the options hash.
452
- end
453
-
454
447
  def when_bound(object_type, *args, &block)
455
448
  case object_type
456
449
  when Class
@@ -8,6 +8,67 @@ module ActiveFacts
8
8
  module API
9
9
 
10
10
  class RoleValues #:nodoc:
11
+ attr_accessor :sort
12
+
13
+ def initialize sort = false
14
+ @sort = !!(sort || ENV[@@af_sort_name ||= "ACTIVEFACTS_SORT"])
15
+ @a = @sort ? RBTree.new : []
16
+ end
17
+
18
+ def +(a)
19
+ if @sort
20
+ @a.values.+(a.is_a?(RoleValues) ? [a] : a)
21
+ else
22
+ @a.+(a.is_a?(RoleValues) ? [a] : a)
23
+ end
24
+ end
25
+
26
+ def to_a
27
+ @sort ? @a.values : @a
28
+ end
29
+
30
+ def keys
31
+ @sort ? @a.keys : @a
32
+ end
33
+
34
+ def single
35
+ size > 1 ? nil : to_a[0]
36
+ end
37
+
38
+ def form_key a
39
+ KeyArray.new(Array(a))
40
+ end
41
+
42
+ def add_instance(value, key)
43
+ if @sort
44
+ @a[form_key(key)] = value
45
+ else
46
+ @a << value
47
+ end
48
+ end
49
+
50
+ def delete_instance(value, key)
51
+ if @sort
52
+ deleted = @a.delete(form_key(key))
53
+ else
54
+ deleted = @a.delete(value)
55
+ end
56
+
57
+ # Test code:
58
+ unless deleted
59
+ p @a
60
+ p value
61
+ debugger
62
+ true
63
+ end
64
+
65
+ end
66
+
67
+ def verbalise
68
+ a = @sort ? @a.values : @a
69
+ "[#{a.map(&:verbalise).join(", ")}]"
70
+ end
71
+
11
72
  # Paranoia. Because of changes in the implementation, I need to catch old code that calls these delegates incorrectly
12
73
  def self.def_single_delegator(accessor, method, *expected_arities)
13
74
  str = %{
@@ -15,12 +76,24 @@ module ActiveFacts
15
76
  if #{expected_arities.size == 0 ? "block" : "!block || !#{expected_arities.inspect}.include?(block.arity)" }
16
77
  raise ArgumentError.new("Arity mismatch on #{name}\##{method}, got \#{block ? block.arity : 'none'} want #{expected_arities.inspect} at \#{caller*"\n\t"})")
17
78
  end
18
- #{accessor}.__send__(:#{method}, *args, &block)
79
+ if @sort
80
+ #{accessor}.values.__send__(:#{method}, *args, &block)
81
+ else
82
+ #{accessor}.__send__(:#{method}, *args, &block)
83
+ end
19
84
  end
20
85
  }
21
86
  eval(str)
22
87
  end
23
88
 
89
+ def include? v
90
+ if @sort
91
+ @a.include?(form_key(v))
92
+ else
93
+ @a.include?(v)
94
+ end
95
+ end
96
+
24
97
  def_single_delegator :@a, :all?, 1
25
98
  def_single_delegator :@a, :empty?
26
99
  def_single_delegator :@a, :include?
@@ -35,28 +108,6 @@ module ActiveFacts
35
108
  def_single_delegator :@a, :each, *([1] + Array(defined?(::RSpec) ? -2 : nil))
36
109
  def_single_delegator :@a, :detect, 1, *([1] + Array(defined?(::RSpec) ? -2 : nil))
37
110
  def_single_delegator :@a, :map, 1, -1
38
-
39
- def initialize
40
- @a = []
41
- end
42
-
43
- def +(a)
44
- @a.+(a.is_a?(RoleValues) ? [a] : a)
45
- end
46
-
47
- def single
48
- size > 1 ? nil : @a[0]
49
- end
50
-
51
- def update(old, value)
52
- @a.delete(old) if old
53
- @a << value if value
54
- end
55
-
56
- def verbalise
57
- "[#{@a.map(&:verbalise).join(", ")}]"
58
- end
59
111
  end
60
-
61
112
  end
62
113
  end
@@ -59,7 +59,7 @@ class Class
59
59
  # Make this Class into a ObjectType and if necessary its module into a Vocabulary.
60
60
  # The parameters are the names (Symbols) of the identifying roles.
61
61
  def identified_by *args, &b
62
- raise InvalidEntityException(self) if respond_to? :value_type # Don't make a ValueType into an EntityType
62
+ raise ActiveFacts::API::InvalidEntityException.new(self) if respond_to? :value_type # Don't make a ValueType into an EntityType
63
63
 
64
64
  # The inclusion of instance methods triggers ClassMethods to be included in the class too
65
65
  include ActiveFacts::API::Entity
@@ -7,9 +7,7 @@
7
7
 
8
8
  # Define Infinity as a constant, if it's not already defined:
9
9
  # We use this to define open-ended ranges.
10
- begin
11
- Object.const_get("Infinity")
12
- rescue NameError
10
+ unless Object.const_defined?("Infinity")
13
11
  Infinity = 1.0/0.0
14
12
  end
15
13
 
@@ -40,7 +40,7 @@ module ActiveFacts
40
40
  # REVISIT: args could be a hash, with keys :length, :scale, :unit, :allow
41
41
  options = (args[-1].is_a?(Hash) ? args.pop : {})
42
42
  options.each do |key, value|
43
- raise UnrecognisedOptionsException.new('value_type', basename, key) unless respond_to?(key)
43
+ raise UnrecognisedOptionsException.new('ValueType', basename, key) unless respond_to?(key)
44
44
  send(key, value)
45
45
  end
46
46
  end
@@ -141,7 +141,7 @@ module ActiveFacts
141
141
  class << klass
142
142
  def new_instance constellation, *args
143
143
  instance = allocate
144
- instance.instance_variable_set("@constellation", constellation)
144
+ instance.instance_variable_set(@@constellation_variable_name ||= "@constellation", constellation)
145
145
  instance.send(:initialize, *args)
146
146
  instance
147
147
  end
@@ -32,7 +32,7 @@ module ActiveFacts
32
32
  __bind(camel)
33
33
  c
34
34
  else
35
- if defined?(camel)
35
+ if const_defined?(camel)
36
36
  begin
37
37
  const_get(camel)
38
38
  rescue NameError
@@ -55,11 +55,12 @@ module ActiveFacts
55
55
 
56
56
  def verbalise
57
57
  "Vocabulary #{name}:\n\t" +
58
- @object_type.keys.sort.map{|object_type|
59
- c = @object_type[object_type]
60
- __bind(c.basename)
61
- c.verbalise + "\n\t\t// Roles played: " + c.roles.verbalise
62
- }*"\n\t"
58
+ @object_type.keys.sort.map do |object_type|
59
+ c = @object_type[object_type]
60
+ __bind(c.basename)
61
+ c.verbalise + "\n\t\t// Roles played: " + c.roles.verbalise
62
+ end.
63
+ join("\n\t")
63
64
  end
64
65
 
65
66
  def __add_object_type(klass) #:nodoc:
@@ -18,7 +18,7 @@ module ActiveFacts
18
18
  # First time, initialise the tracing environment
19
19
  @indent = 0
20
20
  @keys = {}
21
- if (e = ENV["TRACE"])
21
+ if (e = ENV[@@trace_name ||= "TRACE"])
22
22
  e.split(/[^_a-zA-Z0-9]/).each{|k| enable(k) }
23
23
  if @keys[:help]
24
24
  at_exit {
@@ -79,19 +79,19 @@ describe "A Constellation instance" do
79
79
 
80
80
  it "should complain when accessing a non-class as a method" do
81
81
  Mod::Foo = 23
82
- lambda { @constellation.Foo }.should raise_error
82
+ lambda { @constellation.Foo }.should raise_error(NoMethodError)
83
83
  end
84
84
 
85
85
  it "should complain when accessing a class that isn't an object type" do
86
86
  class Mod::Bar; end
87
- proc { @constellation.Bar }.should raise_error
88
- proc { @constellation.instances[Mod::Bar] }.should raise_error
87
+ proc { @constellation.Bar }.should raise_error(NoMethodError)
88
+ proc { @constellation.instances[Mod::Bar] }.should raise_error(ActiveFacts::API::InvalidObjectType)
89
89
  end
90
90
 
91
91
  it "should deny handling an object type defined outside the current module" do
92
92
  class ::Bar; end
93
- lambda { @constellation.Bar }.should raise_error
94
- lambda { @constellation.instances[Bar] }.should raise_error
93
+ lambda { @constellation.Bar }.should raise_error(NoMethodError)
94
+ lambda { @constellation.instances[Bar] }.should raise_error(ActiveFacts::API::InvalidObjectType)
95
95
  end
96
96
 
97
97
  it "should allow inspection" do
@@ -201,7 +201,7 @@ describe "A Constellation instance" do
201
201
  it "Should raise an exception with assigning a role whose referent (object type) has not yet been defined" do
202
202
  n = @constellation.Name("Fred")
203
203
  # This does not raise the "settable_roles_exception". I'm no longer sure how I did this, so I can't get coverage on this code :(
204
- proc { n.undefined_role = 'foo' }.should raise_error
204
+ proc { n.undefined_role = 'foo' }.should raise_error(NoMethodError)
205
205
  end
206
206
 
207
207
  # Maybe not complete yet
@@ -429,7 +429,7 @@ describe "A Constellation instance" do
429
429
  has_one :thingummy, :class => Outside::Other
430
430
  end
431
431
  end
432
- }.should raise_error
432
+ }.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
433
433
  end
434
434
 
435
435
  it "should disallow unrecognised supertypes" do
@@ -514,7 +514,7 @@ describe "A Constellation instance" do
514
514
  supertypes :name
515
515
  end
516
516
  end
517
- }.should raise_error
517
+ }.should raise_error(ActiveFacts::API::InvalidSupertypeException)
518
518
  end
519
519
 
520
520
  it "should error on invalid :class values" do
@@ -524,7 +524,7 @@ describe "A Constellation instance" do
524
524
  has_one :Name, :class => 3
525
525
  end
526
526
  end
527
- }.should raise_error
527
+ }.should raise_error(ArgumentError)
528
528
  end
529
529
 
530
530
  it "should error on misleading :class values" do
@@ -534,7 +534,7 @@ describe "A Constellation instance" do
534
534
  has_one :Name, :class => Extra
535
535
  end
536
536
  end
537
- }.should raise_error
537
+ }.should raise_error(NameError)
538
538
  end
539
539
 
540
540
  it "should allow assert using an object of the same type" do
@@ -572,6 +572,6 @@ describe "A Constellation instance" do
572
572
  lambda {
573
573
  # Disallowed because it re-assigns the auto_counter_val identification value
574
574
  p.employer = [ "foo", {:auto_counter_val => :new}]
575
- }.should raise_error
575
+ }.should raise_error(ActiveFacts::API::TypeConflictException)
576
576
  end
577
577
  end
@@ -364,7 +364,7 @@ describe "An instance of every type of ObjectType" do
364
364
  a = c.AutoCounterVal(:new)
365
365
  lambda {
366
366
  b = 2 + a
367
- }.should raise_error
367
+ }.should raise_error(TypeError)
368
368
  a.assign(3)
369
369
  lambda {
370
370
  b = 2 + a
@@ -376,21 +376,21 @@ describe "An instance of every type of ObjectType" do
376
376
  c = ActiveFacts::API::Constellation.new(Mod)
377
377
  lambda {
378
378
  c.TestByInt(:int_val => nil)
379
- }.should raise_error
379
+ }.should raise_error(ActiveFacts::API::MissingMandatoryRoleValueException)
380
380
  end
381
381
 
382
382
  it "should complain when too many identifying values are provided for an entity" do
383
383
  c = ActiveFacts::API::Constellation.new(Mod)
384
384
  lambda {
385
385
  c.TestByInt(2, 3)
386
- }.should raise_error
386
+ }.should raise_error(ActiveFacts::API::UnexpectedIdentifyingValueException)
387
387
  end
388
388
 
389
389
  it "should complain when wrong type is used for an entity" do
390
390
  c = ActiveFacts::API::Constellation.new(Mod)
391
391
  lambda {
392
392
  c.TestByInt("Not an Int")
393
- }.should raise_error
393
+ }.should raise_error(ArgumentError)
394
394
  end
395
395
 
396
396
  it "should handle a non-mandatory missing identifying role" do
@@ -96,6 +96,35 @@ describe "Roles" do
96
96
  }.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
97
97
  end
98
98
 
99
+ it "should prevent usage of undefined options on a role" do
100
+ lambda {
101
+ module Mod
102
+ class Existing1 < String
103
+ value_type
104
+ has_one :name, :foo => :anything
105
+ end
106
+ end
107
+ }.should raise_error(ActiveFacts::API::UnrecognisedOptionsException)
108
+
109
+ lambda {
110
+ module Mod
111
+ class Existing1 < String
112
+ value_type
113
+ one_to_one :name, :foo => :anything
114
+ end
115
+ end
116
+ }.should raise_error(ActiveFacts::API::UnrecognisedOptionsException)
117
+
118
+ lambda {
119
+ module Mod
120
+ class Existing1 < String
121
+ value_type
122
+ maybe :is_broken, :foo => :anything
123
+ end
124
+ end
125
+ }.should raise_error(ActiveFacts::API::UnrecognisedOptionsException)
126
+ end
127
+
99
128
  it "should provide value type metadata" do
100
129
  Mod::Name.length.should == 40
101
130
  Mod::Name.scale.should == 0
@@ -37,7 +37,7 @@ describe "An Entity Type" do
37
37
  has_one :name
38
38
  end
39
39
  end
40
- end.should raise_error
40
+ end.should raise_error(ActiveFacts::API::InvalidIdentificationException)
41
41
  end
42
42
 
43
43
  describe "when asserted" do
@@ -84,7 +84,7 @@ describe "An Entity Type" do
84
84
  it "should fail if the new value already exists" do
85
85
  proc do
86
86
  @fly.name = 'Acme'
87
- end.should raise_error
87
+ end.should raise_error(ActiveFacts::API::DuplicateIdentifyingValueException)
88
88
  end
89
89
 
90
90
  it "should not fail if the new value is self" do
@@ -234,7 +234,7 @@ describe "An Entity Type" do
234
234
  one_to_one :number # Error, invalid identifier
235
235
  end
236
236
  end
237
- end.should raise_error
237
+ end.should raise_error(ActiveFacts::API::InvalidIdentificationException)
238
238
  end
239
239
 
240
240
  describe "when asserted" do
@@ -294,7 +294,7 @@ describe "An Entity Type" do
294
294
 
295
295
  it "should fail if the new value already exists" do
296
296
  @c.Room(@b, 102)
297
- lambda { @r.number = 102 }.should raise_error
297
+ lambda { @r.number = 102 }.should raise_error(ActiveFacts::API::DuplicateIdentifyingValueException)
298
298
  end
299
299
 
300
300
  describe "to a previously-nonexistent value" do
@@ -337,6 +337,7 @@ describe "An Entity Type" do
337
337
  end
338
338
 
339
339
  it "the old value's back-reference is set to nil" do
340
+ # @rn.all_room.should_not include @r
340
341
  @rn.all_room.to_a.should_not include @r
341
342
  end
342
343
 
@@ -30,7 +30,7 @@ describe 'identity change on subtype' do
30
30
  end
31
31
 
32
32
  it "should fail if the value is the same" do
33
- lambda { @b = @constellation.EntityB(123, 'abc') }.should raise_error
33
+ lambda { @b = @constellation.EntityB(123, 'abc') }.should raise_error(ActiveFacts::API::UnexpectedIdentifyingValueException)
34
34
  end
35
35
 
36
36
  context "on a deep-subtype" do
@@ -60,4 +60,4 @@ describe 'identity change on subtype' do
60
60
  @c.value_a.should == 987
61
61
  end
62
62
  end
63
- end
63
+ end
@@ -75,12 +75,12 @@ describe "Entity Type class definitions" do
75
75
  Mod::Person.roles.include?(:name).should be_true
76
76
  end
77
77
 
78
- it "should fail on a ValClass" do
78
+ it "should fail on a ValueType" do
79
79
  lambda{
80
80
  class SomeClass < String
81
- identified_by
81
+ identified_by :foo
82
82
  end
83
- }.should raise_error
83
+ }.should raise_error(ActiveFacts::API::InvalidEntityException)
84
84
  end
85
85
 
86
86
  it "should return the identifying roles" do
@@ -88,15 +88,15 @@ describe "Entity Type class definitions" do
88
88
  end
89
89
 
90
90
  it "should prevent a role name from matching a object_type that exists unless that object_type is the counterpart" do
91
- lambda {
92
- module Mod
93
- class LegalEntity
94
- end
95
- class Bad
96
- identified_by :name
97
- has_one :name, LegalEntity
98
- end
99
- end
100
- }.should raise_error
91
+ proc do
92
+ module Mod
93
+ class LegalEntity
94
+ end
95
+ class Bad
96
+ identified_by :name
97
+ has_one :name, :class => LegalEntity
98
+ end
99
+ end
100
+ end.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
101
101
  end
102
102
  end
@@ -38,7 +38,7 @@ describe "Multi-part identifiers" do
38
38
  end
39
39
 
40
40
  it "should sort child keys in the instance index" do
41
- pending "Key sorting is not supported in this version" unless @p.all_child.respond_to? :keys
41
+ pending "Key sorting is not supported on this index" unless @c.Child.sort
42
42
  @c.Child.keys.should == [[[@p.parent_id], 0], [[@p.parent_id], 1], [[@p.parent_id], 2]]
43
43
  @c.Child.map{|k, c| c.position}.should == [@c0.position, @c1.position, @c2.position]
44
44
  end
@@ -47,7 +47,7 @@ describe "AutoCounter Value Type instances" do
47
47
  it "should allow prevent invalid role assignment" do
48
48
  lambda {
49
49
  @thing.thing_id = "foo"
50
- }.should raise_error
50
+ }.should raise_error(ArgumentError)
51
51
  end
52
52
 
53
53
  it "should not allow its value to be re-assigned" do
@@ -57,7 +57,7 @@ describe "AutoCounter Value Type instances" do
57
57
  lambda {
58
58
  @thing.thing_id.assign(4)
59
59
  #@thing.thing_id.assign(@thing_id)
60
- }.should raise_error
60
+ }.should raise_error(ArgumentError)
61
61
  end
62
62
 
63
63
  it "should allow an existing counter to be re-used" do
@@ -72,7 +72,7 @@ describe "AutoCounter Value Type instances" do
72
72
  it "should not allow a counter to be cloned" do
73
73
  lambda {
74
74
  @thing_id.clone
75
- }.should raise_error
75
+ }.should raise_error(RuntimeError)
76
76
  end
77
77
 
78
78
  it "should allow an existing counter-identified object to be re-used" do
@@ -47,7 +47,7 @@ describe "Guid Value Type instances" do
47
47
  it "should allow prevent invalid role assignment" do
48
48
  lambda {
49
49
  @thing.thing_id = "foo"
50
- }.should raise_error
50
+ }.should raise_error(ArgumentError)
51
51
  end
52
52
 
53
53
  it "should allow an existing guid to be re-used" do
@@ -101,7 +101,7 @@ describe "Value Type class definitions" do
101
101
  class NameNotString
102
102
  value_type
103
103
  end
104
- }.should raise_error
104
+ }.should raise_error(NameError)
105
105
  end
106
106
 
107
107
  it "should allow configuration of Role value through constructor using role name" do
metadata CHANGED
@@ -1,68 +1,60 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activefacts-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
5
- prerelease:
4
+ version: 0.9.8
6
5
  platform: ruby
7
6
  authors:
8
7
  - Clifford Heath
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-01-29 00:00:00.000000000 Z
11
+ date: 2013-11-13 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rbtree-pure
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
- version: '0'
33
+ version: '10.1'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
- version: '0'
40
+ version: '10.1'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: jeweler
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: rspec
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ~>
68
60
  - !ruby/object:Gem::Version
@@ -70,7 +62,6 @@ dependencies:
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ~>
76
67
  - !ruby/object:Gem::Version
@@ -78,55 +69,48 @@ dependencies:
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: ruby-debug
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - '>='
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - '>='
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: debugger
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ! '>='
87
+ - - '>='
100
88
  - !ruby/object:Gem::Version
101
89
  version: '0'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ! '>='
94
+ - - '>='
108
95
  - !ruby/object:Gem::Version
109
96
  version: '0'
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: pry
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ! '>='
101
+ - - '>='
116
102
  - !ruby/object:Gem::Version
117
103
  version: '0'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
- - - ! '>='
108
+ - - '>='
124
109
  - !ruby/object:Gem::Version
125
110
  version: '0'
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: rspec
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
115
  - - ~>
132
116
  - !ruby/object:Gem::Version
@@ -134,7 +118,6 @@ dependencies:
134
118
  type: :development
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
122
  - - ~>
140
123
  - !ruby/object:Gem::Version
@@ -142,7 +125,6 @@ dependencies:
142
125
  - !ruby/object:Gem::Dependency
143
126
  name: bundler
144
127
  requirement: !ruby/object:Gem::Requirement
145
- none: false
146
128
  requirements:
147
129
  - - ~>
148
130
  - !ruby/object:Gem::Version
@@ -150,7 +132,6 @@ dependencies:
150
132
  type: :development
151
133
  prerelease: false
152
134
  version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
135
  requirements:
155
136
  - - ~>
156
137
  - !ruby/object:Gem::Version
@@ -158,7 +139,6 @@ dependencies:
158
139
  - !ruby/object:Gem::Dependency
159
140
  name: jeweler
160
141
  requirement: !ruby/object:Gem::Requirement
161
- none: false
162
142
  requirements:
163
143
  - - ~>
164
144
  - !ruby/object:Gem::Version
@@ -166,7 +146,6 @@ dependencies:
166
146
  type: :development
167
147
  prerelease: false
168
148
  version_requirements: !ruby/object:Gem::Requirement
169
- none: false
170
149
  requirements:
171
150
  - - ~>
172
151
  - !ruby/object:Gem::Version
@@ -174,34 +153,24 @@ dependencies:
174
153
  - !ruby/object:Gem::Dependency
175
154
  name: rdoc
176
155
  requirement: !ruby/object:Gem::Requirement
177
- none: false
178
156
  requirements:
179
- - - ! '>='
157
+ - - '>='
180
158
  - !ruby/object:Gem::Version
181
159
  version: 2.4.2
182
160
  type: :development
183
161
  prerelease: false
184
162
  version_requirements: !ruby/object:Gem::Requirement
185
- none: false
186
163
  requirements:
187
- - - ! '>='
164
+ - - '>='
188
165
  - !ruby/object:Gem::Version
189
166
  version: 2.4.2
190
- description: ! '
167
+ description: |2
191
168
 
192
169
  The ActiveFacts API is a Ruby DSL for managing constellations of elementary facts.
193
-
194
- Each fact is either existential (a value or an entity), characteristic (boolean)
195
- or
196
-
197
- binary relational (A rel B). Relational facts are consistently co-referenced, so
198
- you
199
-
170
+ Each fact is either existential (a value or an entity), characteristic (boolean) or
171
+ binary relational (A rel B). Relational facts are consistently co-referenced, so you
200
172
  can traverse them efficiently in any direction. Each constellation maintains constraints
201
-
202
173
  over the fact population.
203
-
204
- '
205
174
  email: clifford.heath@gmail.com
206
175
  executables: []
207
176
  extensions: []
@@ -260,29 +229,25 @@ files:
260
229
  homepage: http://github.com/cjheath/activefacts-api
261
230
  licenses:
262
231
  - MIT
232
+ metadata: {}
263
233
  post_install_message:
264
234
  rdoc_options: []
265
235
  require_paths:
266
236
  - lib
267
237
  required_ruby_version: !ruby/object:Gem::Requirement
268
- none: false
269
238
  requirements:
270
- - - ! '>='
239
+ - - '>='
271
240
  - !ruby/object:Gem::Version
272
241
  version: '0'
273
- segments:
274
- - 0
275
- hash: -1550200325745257681
276
242
  required_rubygems_version: !ruby/object:Gem::Requirement
277
- none: false
278
243
  requirements:
279
- - - ! '>='
244
+ - - '>='
280
245
  - !ruby/object:Gem::Version
281
246
  version: '0'
282
247
  requirements: []
283
248
  rubyforge_project:
284
- rubygems_version: 1.8.24
249
+ rubygems_version: 2.0.5
285
250
  signing_key:
286
- specification_version: 3
251
+ specification_version: 4
287
252
  summary: A fact-based data model DSL and API
288
253
  test_files: []