activefacts-api 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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: []