activefacts-api 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -6,4 +6,4 @@ rvm:
6
6
  - jruby-18mode
7
7
  - jruby-19mode
8
8
  - rbx-18mode
9
- - rbx-19mode
9
+ - rbx-19mode
data/Gemfile CHANGED
@@ -5,6 +5,9 @@ gem 'rake', :group => [:development, :test]
5
5
  group :development do
6
6
  gem 'jeweler'
7
7
  gem 'rspec', '~>2.6.0'
8
+ gem 'ruby-debug', :platforms => [:mri_18]
9
+ gem 'debugger', :platforms => [:mri_19]
10
+ gem 'pry', :platforms => [:jruby, :rbx]
8
11
  end
9
12
 
10
13
  group :test do
data/Rakefile CHANGED
@@ -31,22 +31,41 @@ require 'rspec/core'
31
31
  require 'rspec/core/rake_task'
32
32
  require 'rdoc/task'
33
33
 
34
+ gem "rspec", :require => "spec/rake/spectask"
35
+
34
36
  task :default => :spec
35
37
 
36
38
  desc "Run Rspec tests"
37
- RSpec::Core::RakeTask.new(:spec)
39
+ RSpec::Core::RakeTask.new(:spec) do |t|
40
+ t.rspec_opts = %w{-f d}
41
+ end
42
+
43
+ namespace :spec do
44
+ namespace :rubies do
45
+ SUPPORTED_RUBIES = %w{ 1.8.7 1.9.2 1.9.3 jruby-1.7.0 rbx }
46
+
47
+ desc "Run Rspec tests on all supported rubies"
48
+ task :all_tasks => [:install_gems, :exec]
49
+
50
+ desc "Run `bundle install` on all rubies"
51
+ task :install_gems do
52
+ sh %{ rvm #{SUPPORTED_RUBIES.join(',')} exec bundle install }
53
+ end
54
+
55
+ desc "Run `bundle exec rake` on all rubies"
56
+ task :exec do
57
+ sh %{ rvm #{SUPPORTED_RUBIES.join(',')} exec bundle exec rake spec }
58
+ end
59
+ end
60
+ end
38
61
 
39
62
  desc "Run RSpec tests and produce coverage files (results viewable in coverage/index.html)"
40
63
  RSpec::Core::RakeTask.new(:coverage) do |spec|
41
64
  if RUBY_VERSION < '1.9'
42
- spec.rcov_opts = [
43
- '--exclude', 'spec',
44
- '--exclude', 'lib/activefacts/tracer.rb',
45
- '--exclude', 'gem/*'
46
- ]
65
+ spec.rcov_opts = %{ --exclude spec --exclude lib/activefacts/tracer.rb --exclude gem/* }
47
66
  spec.rcov = true
48
67
  else
49
- spec.rspec_opts = ['--require', 'simplecov_helper']
68
+ spec.rspec_opts = %w{ --require simplecov_helper }
50
69
  end
51
70
  end
52
71
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.2
1
+ 0.9.3
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "activefacts-api"
8
- s.version = "0.9.2"
8
+ s.version = "0.9.3"
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 = "2012-10-17"
12
+ s.date = "2012-11-01"
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 = [
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
31
31
  "lib/activefacts/api/constellation.rb",
32
32
  "lib/activefacts/api/entity.rb",
33
33
  "lib/activefacts/api/exceptions.rb",
34
+ "lib/activefacts/api/guid.rb",
34
35
  "lib/activefacts/api/instance.rb",
35
36
  "lib/activefacts/api/instance_index.rb",
36
37
  "lib/activefacts/api/numeric.rb",
@@ -54,6 +55,8 @@ Gem::Specification.new do |s|
54
55
  "spec/object_type/entity_type/entity_type_spec.rb",
55
56
  "spec/object_type/entity_type/multipart_identification_spec.rb",
56
57
  "spec/object_type/value_type/autocounter_spec.rb",
58
+ "spec/object_type/value_type/date_time_spec.rb",
59
+ "spec/object_type/value_type/guid_spec.rb",
57
60
  "spec/object_type/value_type/numeric_spec.rb",
58
61
  "spec/object_type/value_type/value_type_spec.rb",
59
62
  "spec/simplecov_helper.rb",
@@ -72,6 +75,9 @@ Gem::Specification.new do |s|
72
75
  s.add_development_dependency(%q<rake>, [">= 0"])
73
76
  s.add_development_dependency(%q<jeweler>, [">= 0"])
74
77
  s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
78
+ s.add_development_dependency(%q<ruby-debug>, [">= 0"])
79
+ s.add_development_dependency(%q<debugger>, [">= 0"])
80
+ s.add_development_dependency(%q<pry>, [">= 0"])
75
81
  s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
76
82
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
77
83
  s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
@@ -80,6 +86,9 @@ Gem::Specification.new do |s|
80
86
  s.add_dependency(%q<rake>, [">= 0"])
81
87
  s.add_dependency(%q<jeweler>, [">= 0"])
82
88
  s.add_dependency(%q<rspec>, ["~> 2.6.0"])
89
+ s.add_dependency(%q<ruby-debug>, [">= 0"])
90
+ s.add_dependency(%q<debugger>, [">= 0"])
91
+ s.add_dependency(%q<pry>, [">= 0"])
83
92
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
84
93
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
85
94
  s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
@@ -89,6 +98,9 @@ Gem::Specification.new do |s|
89
98
  s.add_dependency(%q<rake>, [">= 0"])
90
99
  s.add_dependency(%q<jeweler>, [">= 0"])
91
100
  s.add_dependency(%q<rspec>, ["~> 2.6.0"])
101
+ s.add_dependency(%q<ruby-debug>, [">= 0"])
102
+ s.add_dependency(%q<debugger>, [">= 0"])
103
+ s.add_dependency(%q<pry>, [">= 0"])
92
104
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
93
105
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
94
106
  s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
@@ -43,7 +43,9 @@ module ActiveFacts
43
43
  def initialize(vocabulary)
44
44
  @vocabulary = vocabulary
45
45
  @instances = Hash.new do |h,k|
46
- raise "A constellation over #{@vocabulary.name} can only index instances of object_types in that vocabulary, not #{k.inspect}" unless k.is_a?(Class) and k.modspace == vocabulary
46
+ unless k.is_a?(Class) and k.modspace == vocabulary
47
+ raise "A constellation over #{@vocabulary.name} can only index instances of classes in that vocabulary, not #{k.inspect}"
48
+ end
47
49
  h[k] = InstanceIndex.new(self, k)
48
50
  end
49
51
  end
@@ -66,27 +68,6 @@ module ActiveFacts
66
68
  self
67
69
  end
68
70
 
69
- =begin
70
- def assert *args
71
- case
72
- when args.size >= 1
73
- args.each do |arg|
74
- assert arg
75
- end
76
- when args[0].is_a?(Hash)
77
- args[0].each do |key, value|
78
- klass_name = key.is_a?(Symbol) ? key.to_s.camelcase : key.to_s
79
- klass = vocabulary.const_get(klass_name)
80
- send(klass_name).assert(*Array(value))
81
- end
82
- else
83
- args.each do |arg|
84
- assert(arg)
85
- end
86
- end
87
- end
88
- =end
89
-
90
71
  # Constellations verbalise all members of all classes in alphabetical order, showing
91
72
  # non-identifying role values as well
92
73
  def verbalise
@@ -137,8 +118,8 @@ module ActiveFacts
137
118
  # With no parameters, return the collection of all instances of that object_type.
138
119
  # With parameters, assert an instance of the object_type identified by the values passed as args.
139
120
  def method_missing(m, *args, &b)
140
- if klass = @vocabulary.const_get(m) and klass.is_a?(Class) and klass.respond_to?(:assert_instance)
141
-
121
+ klass = @vocabulary.const_get(m)
122
+ if klass and klass.is_a?(Class) and klass.respond_to?(:assert_instance)
142
123
  (class << self; self; end).
143
124
  send(:define_method, sym = m.to_sym) do |*args|
144
125
  instance_index = @instances[klass]
@@ -58,10 +58,41 @@ module ActiveFacts
58
58
  # Assign the identifying roles in order. Any other roles will be assigned by our caller
59
59
  klass.identifying_role_names.zip(args).each do |role_name, value|
60
60
  role = self.class.roles(role_name)
61
- send(role.setter, value)
61
+ begin
62
+ send(role.setter, value)
63
+ rescue NoMethodError => e
64
+ raise settable_roles_exception(e, role_name)
65
+ end
62
66
  end
63
67
  end
64
68
 
69
+ def settable_roles_exception e, role_name
70
+ n = e.class.new(
71
+ "#{self.class} has no setter for #{role_name}.\n" +
72
+ "Settable roles are #{settable_roles*', '}.\n" +
73
+ (if self.class.vocabulary.delayed.empty?
74
+ ''
75
+ else
76
+ "This could be because the following expected object types are still not defined: #{self.class.vocabulary.delayed.keys.sort*', '}\n"
77
+ end
78
+ )
79
+ )
80
+ n.set_backtrace(e.backtrace)
81
+ n
82
+ end
83
+
84
+ def settable_roles
85
+ ([self.class]+self.class.supertypes_transitive).
86
+ map do |k|
87
+ k.roles.
88
+ map do |name, role|
89
+ role.unique ? name : nil
90
+ end.
91
+ compact
92
+ end.
93
+ flatten
94
+ end
95
+
65
96
  def inspect #:nodoc:
66
97
  inc = constellation ? " in #{constellation.inspect}" : ""
67
98
  # REVISIT: Where there are one-to-one roles, this cycles
@@ -196,7 +227,7 @@ module ActiveFacts
196
227
  end
197
228
  if arg == nil # But not false
198
229
  if role.mandatory
199
- raise "You must provide a #{role.counterpart.object_type.name} to identify a #{basename}"
230
+ raise MissingMandatoryRoleValueException.new(self, role)
200
231
  end
201
232
  else
202
233
  role.counterpart_object_type.identifying_role_values(*arg)
@@ -246,13 +277,17 @@ module ActiveFacts
246
277
  elsif !arg
247
278
  value = role_key = nil
248
279
  else
280
+ =begin
281
+ # REVISIT; These next few lines are bogus; they generate TypeError exceptions which are caught and ignored
282
+ # A new approach will follow shortly which won't @create_instances that won't be needed
249
283
  if role.counterpart.object_type.is_entity_type
250
284
  add = !constellation.send(role.counterpart.object_type.basename.to_sym).include?([arg])
251
285
  else
252
286
  add = !constellation.send(role.counterpart.object_type.basename.to_sym).include?(arg)
253
287
  end
288
+ =end
254
289
  value, role_key = role.counterpart.object_type.assert_instance(constellation, Array(arg))
255
- @created_instances << [role.counterpart, value] if add
290
+ # @created_instances << [role.counterpart, value] if add
256
291
  end
257
292
  key << role_key
258
293
  value
@@ -6,7 +6,34 @@
6
6
 
7
7
  module ActiveFacts
8
8
  module API
9
- class DuplicateIdentifyingValueException < StandardError
9
+ class ActiveFactsException < StandardError
10
+ end
11
+
12
+ class ActiveFactsSchemaException < ActiveFactsException
13
+ end
14
+
15
+ class ActiveFactsRuntimeException < ActiveFactsException
16
+ end
17
+
18
+ class CrossVocabularyRoleException < ActiveFactsSchemaException
19
+ def initialize klass, vocabulary
20
+ super "#{klass} must be an object type in #{vocabulary.name}"
21
+ end
22
+ end
23
+
24
+ class RoleNotDefinedException < ActiveFactsRuntimeException
25
+ def initialize klass, role_name
26
+ super "Role #{klass.basename}.#{role_name} is not defined"
27
+ end
28
+ end
29
+
30
+ class MissingMandatoryRoleValueException < ActiveFactsRuntimeException
31
+ def initialize klass, role
32
+ super "A #{role.counterpart.object_type.basename} is required to satisfy the #{role.name.inspect} role of #{klass.basename}"
33
+ end
34
+ end
35
+
36
+ class DuplicateIdentifyingValueException < ActiveFactsRuntimeException
10
37
  def initialize(desc)
11
38
  super("Illegal attempt to assert #{desc[:class].basename} having identifying value" +
12
39
  " (#{desc[:role].name} is #{desc[:value].verbalise})," +
@@ -0,0 +1,57 @@
1
+ require 'delegate'
2
+ require 'date'
3
+ require 'securerandom'
4
+
5
+ unless defined? SecureRandom.uuid
6
+ # I think this only applies to 1.8.6 (and JRuby/Rubinius in 1.8 mode) now:
7
+ def SecureRandom.uuid
8
+ hex(16).sub(/(........)(....)(....)(....)(............)/,'\1-\2-\3-\4-\5')
9
+ end
10
+ end
11
+
12
+ # The Guid class is what it says on the packet, but you can assert a :new one.
13
+ class Guid
14
+ def initialize(i = :new)
15
+ if i == :new
16
+ @value = SecureRandom.uuid.freeze
17
+ elsif (v = i.to_s).length == 36 and !(v !~ /[^0-9a-f]/i)
18
+ @value = v.clone.freeze
19
+ else
20
+ raise "Illegal non-Guid value #{i.inspect} given for Guid"
21
+ end
22
+ end
23
+
24
+ def to_s
25
+ @value
26
+ end
27
+
28
+ # if the value is unassigned, it equal?(:new).
29
+ def equal? value
30
+ @value == value
31
+ end
32
+
33
+ def inspect
34
+ "\#<Guid #{@value}>"
35
+ end
36
+
37
+ def hash #:nodoc:
38
+ @value.hash
39
+ end
40
+
41
+ def eql?(o) #:nodoc:
42
+ to_s.eql?(o.to_s)
43
+ end
44
+
45
+ # def self.inherited(other) #:nodoc:
46
+ # def other.identifying_role_values(*args)
47
+ # return nil if args == [:new] # A new object has no identifying_role_values
48
+ # if args.size == 1
49
+ # return args[0] if args[0].is_a?(AutoCounter)
50
+ # return args[0].send(self.basename.snakecase.to_sym) if args[0].respond_to?(self.basename.snakecase.to_sym)
51
+ # end
52
+ # return new(*args)
53
+ # end
54
+ # super
55
+ # end
56
+
57
+ end
@@ -44,7 +44,17 @@ module ActiveFacts
44
44
  if args.size == 1 && args[0].is_a?(@klass)
45
45
  key = args[0].identifying_role_values
46
46
  else
47
- key = @klass.identifying_role_values(*args) rescue nil
47
+ begin
48
+ key = @klass.identifying_role_values(*args)
49
+ rescue TypeError => e
50
+ # This happens (and should not) during assert_instance when checking
51
+ # for new asserts of identifying values that might get rolled back
52
+ # when the assert fails (for example because of an implied subtyping change)
53
+ key = nil
54
+ rescue ActiveFactsRuntimeException => e
55
+ # This is currently only known to happen during a retract()
56
+ key = nil
57
+ end
48
58
  end
49
59
 
50
60
  @hash[key]
@@ -100,6 +100,7 @@ class ::Date
100
100
  elsif (a.size == 1 && a[0].is_a?(String))
101
101
  parse(a[0])
102
102
  else
103
+ a = [] if a == [nil]
103
104
  civil(*a, &b)
104
105
  end
105
106
  end
@@ -29,13 +29,17 @@ module ActiveFacts
29
29
  unless role = @roles[role_name.to_sym]
30
30
  role = nil
31
31
  supertypes.each do |supertype|
32
- r = supertype.roles(role_name) rescue nil
33
- next unless r
34
- role = r
32
+ begin
33
+ role = supertype.roles(role_name)
34
+ rescue RoleNotDefinedException
35
+ next
36
+ end
35
37
  break
36
38
  end
37
39
  end
38
- raise "Role #{basename}.#{role_name} is not defined" unless role
40
+ unless role
41
+ raise RoleNotDefinedException.new(self, role_name)
42
+ end
39
43
  role
40
44
  else
41
45
  nil
@@ -132,7 +136,7 @@ module ActiveFacts
132
136
  # REVISIT: Need to check all superclass roles recursively, unless we hit a common supertype
133
137
  realise_supertypes(object_type, all_supertypes)
134
138
  end
135
- [(superclass.vocabulary && superclass rescue nil), *@supertypes].compact
139
+ [(superclass.respond_to?(:vocabulary) ? superclass : nil), *@supertypes].compact
136
140
  end
137
141
  end
138
142
 
@@ -140,12 +144,12 @@ module ActiveFacts
140
144
  def supertypes_transitive
141
145
  class_eval do
142
146
  supertypes = []
143
- supertypes << superclass if Module === (superclass.vocabulary rescue nil)
147
+ v = superclass.respond_to?(:vocabulary) ? superclass.vocabulary : nil
148
+ supertypes << superclass if v.kind_of?(Module)
144
149
  supertypes += (@supertypes ||= [])
145
150
  sts = supertypes.inject([]) do |a, t|
146
151
  next if a.include?(t)
147
- a += [t]
148
- a += t.supertypes_transitive rescue []
152
+ a += [t] + t.supertypes_transitive
149
153
  end.uniq
150
154
  sts # The local variable unconfuses rcov
151
155
  end
@@ -236,7 +240,7 @@ module ActiveFacts
236
240
  class_eval do
237
241
  define_method role.getter do |*a|
238
242
  raise "Parameters passed to #{self.class.name}\##{role.name}" if a.size > 0
239
- instance_variable_get(role.variable) rescue nil
243
+ instance_variable_get(role.variable)
240
244
  end
241
245
  end
242
246
  end
@@ -247,7 +251,7 @@ module ActiveFacts
247
251
  class_eval do
248
252
  define_method role.setter do |value|
249
253
 
250
- old = instance_variable_get(role.variable) rescue nil
254
+ old = instance_variable_get(role.variable)
251
255
  return true if old.equal?(value) # Occurs when another instance having the same value is assigned
252
256
 
253
257
  value = role.adapt(@constellation, value) if value
@@ -288,7 +292,7 @@ module ActiveFacts
288
292
  role_var = role.variable
289
293
 
290
294
  # Get old value, and jump out early if it's unchanged:
291
- old = instance_variable_get(role_var) rescue nil
295
+ old = instance_variable_get(role_var)
292
296
  return value if old.equal?(value) # Occurs during one_to_one assignment, for example
293
297
 
294
298
  value = role.adapt(constellation, value) if value
@@ -324,10 +328,9 @@ module ActiveFacts
324
328
  def define_many_to_one_accessor(role)
325
329
  class_eval do
326
330
  define_method role.getter do
327
- unless (r = instance_variable_get(role_var = role.variable) rescue nil)
328
- r = instance_variable_set(role_var, RoleValues.new)
329
- end
330
- r
331
+ role_var = role.variable
332
+ instance_variable_get(role_var) or
333
+ instance_variable_set(role_var, RoleValues.new)
331
334
  end
332
335
  end
333
336
  end
@@ -388,10 +391,12 @@ module ActiveFacts
388
391
  end
389
392
 
390
393
  # resolve the Symbol to a Class now if possible:
391
- resolved = vocabulary.object_type(related) rescue nil
394
+ resolved = vocabulary.object_type(related)
392
395
  related = resolved if resolved
393
396
  if related.is_a?(Class)
394
- raise "#{related} must be an object type in #{vocabulary.name}" unless related.respond_to?(:vocabulary) and related.vocabulary == self.vocabulary
397
+ unless related.respond_to?(:vocabulary) and related.vocabulary == self.vocabulary
398
+ raise CrossVocabularyRoleException.new(related, vocabulary)
399
+ end
395
400
  end
396
401
 
397
402
  if options.delete(:mandatory) == true
@@ -101,7 +101,7 @@ module ActiveFacts
101
101
  role = self
102
102
  klass.class_eval do
103
103
  role_accessor_name = "#{role.name}_role"
104
- unless (method(role_accessor_name) rescue nil)
104
+ unless respond_to?(role_accessor_name)
105
105
  (class << self; self; end).
106
106
  send(:define_method, role_accessor_name) do
107
107
  role
@@ -9,6 +9,7 @@
9
9
  #
10
10
  require 'date'
11
11
  require 'activefacts/api/numeric'
12
+ require 'activefacts/api/guid'
12
13
 
13
14
  module ActiveFacts
14
15
  module API
@@ -23,7 +24,7 @@ module ActiveFacts
23
24
  end
24
25
  # Add the methods that convert our classes into ObjectType types:
25
26
 
26
- ValueClasses = [String, Date, DateTime, Time, Int, Real, AutoCounter, Decimal]
27
+ ValueClasses = [String, Date, DateTime, Time, Int, Real, AutoCounter, Decimal, Guid]
27
28
  ValueClasses.each{|c|
28
29
  c.send :extend, ActiveFacts::API::ValueClass
29
30
  }
@@ -9,7 +9,7 @@
9
9
  # We use this to define open-ended ranges.
10
10
  begin
11
11
  Object.const_get("Infinity")
12
- rescue
12
+ rescue NameError
13
13
  Infinity = 1.0/0.0
14
14
  end
15
15
 
@@ -21,7 +21,9 @@ module ActiveFacts
21
21
  return @object_type unless name
22
22
 
23
23
  if name.is_a? Class
24
- raise "#{name} must be an object type in #{self.name}" unless name.vocabulary == self
24
+ unless name.respond_to?(:vocabulary) and name.vocabulary == self
25
+ raise CrossVocabularyRoleException.new(name, self)
26
+ end
25
27
  return name
26
28
  end
27
29
 
@@ -31,7 +33,7 @@ module ActiveFacts
31
33
  c
32
34
  else
33
35
  begin
34
- const_get("#{self.name}::#{camel}")
36
+ const_get(camel)
35
37
  rescue NameError
36
38
  nil
37
39
  end
@@ -64,22 +66,26 @@ module ActiveFacts
64
66
  end
65
67
 
66
68
  def __delay(object_type_name, args, &block) #:nodoc:
67
- @delayed ||= Hash.new { |h,k| h[k] = [] }
68
- @delayed[object_type_name] << [args, block]
69
+ delayed[object_type_name] << [args, block]
69
70
  end
70
71
 
71
72
  # __bind raises an error if the named class doesn't exist yet.
72
73
  def __bind(object_type_name) #:nodoc:
73
74
  object_type = const_get(object_type_name)
74
- if (@delayed && @delayed.include?(object_type_name))
75
- d = @delayed[object_type_name]
75
+ if (delayed.include?(object_type_name))
76
+ d = delayed[object_type_name]
76
77
  d.each{|(a,b)|
77
78
  b.call(object_type, *a)
78
79
  }
79
- @delayed.delete(object_type_name)
80
+ delayed.delete(object_type_name)
80
81
  end
81
82
  end
82
83
 
84
+ def delayed
85
+ @delayed ||= Hash.new { |h,k| h[k] = [] }
86
+ @delayed
87
+ end
88
+
83
89
  end
84
90
  end
85
91
  end
@@ -26,14 +26,26 @@ module ActiveFacts
26
26
  }
27
27
  end
28
28
  if @keys[:debug]
29
- ['pry', 'debugger', 'ruby-debug'].each do |debugger|
29
+ errors = []
30
+ success = false
31
+ [ENV["DEBUG_PREFERENCE"]].compact+
32
+ [
33
+ 'pry',
34
+ 'debugger',
35
+ 'ruby-debug'
36
+ ].each do |debugger|
30
37
  begin
31
38
  require debugger
32
39
  puts "Loaded "+debugger
40
+ success = true
33
41
  break
34
- rescue LoadError
42
+ rescue LoadError => e
43
+ errors << e
35
44
  end
36
45
  end
46
+ unless success
47
+ puts "Can't load any debugger, failed on:\n#{errors.inspect}"
48
+ end
37
49
  ::Debugger.start rescue nil
38
50
  end
39
51
  end
@@ -8,7 +8,7 @@ describe "A Constellation instance" do
8
8
  Object.send :remove_const, :Mod if Object.const_defined?("Mod")
9
9
  module Mod
10
10
  @base_types = [
11
- Int, Real, AutoCounter, String, Date, DateTime
11
+ Int, Real, AutoCounter, String, Date, DateTime, Decimal, Guid
12
12
  ]
13
13
 
14
14
  # Create a value type and a subtype of that value type for each base type:
@@ -9,7 +9,7 @@ describe "An instance of every type of ObjectType" do
9
9
  module Mod
10
10
  # These are the base value types we're going to test:
11
11
  @base_types = [
12
- Int, Real, AutoCounter, String, Date, DateTime, Decimal
12
+ Int, Real, AutoCounter, String, Date, DateTime, Decimal, Guid
13
13
  ]
14
14
 
15
15
  # Construct the names of the roles they play:
@@ -74,7 +74,13 @@ describe "An instance of every type of ObjectType" do
74
74
  one_to_one :test_by_#{base_type.name.snakecase}
75
75
  end
76
76
  END
77
- Mod.module_eval code
77
+
78
+ begin
79
+ Mod.module_eval code
80
+ rescue Exception => e
81
+ puts "Failure: #{e}"
82
+ puts "Failed on: <<END\n#{code}\nEND"
83
+ end
78
84
  end
79
85
  end
80
86
 
@@ -87,6 +93,7 @@ describe "An instance of every type of ObjectType" do
87
93
  @date = [2008, 04, 19]
88
94
  @date_time = [2008, 04, 19, 10, 28, 14]
89
95
  @decimal = BigDecimal.new('98765432109876543210')
96
+ @guid = '01234567-89ab-cdef-0123-456789abcdef'
90
97
 
91
98
  # Value Type instances
92
99
  @int_value = Mod::IntVal.new(1)
@@ -101,6 +108,7 @@ describe "An instance of every type of ObjectType" do
101
108
  @date_time_value = Mod::DateTimeVal.new d # 2008, 04, 20, 10, 28, 14
102
109
  # This next isn't in the same pattern; it makes a Decimal from a BigDecimal rather than a String (coverage reasons)
103
110
  @decimal_value = Mod::DecimalVal.new(BigDecimal.new('98765432109876543210'))
111
+ @guid_value = Mod::GuidVal.new(:new)
104
112
 
105
113
  # Value SubType instances
106
114
  @int_sub_value = Mod::IntSubVal.new(4)
@@ -112,6 +120,7 @@ describe "An instance of every type of ObjectType" do
112
120
  @date_time_sub_value = Mod::DateTimeSubVal.new(::DateTime.civil(2008, 04, 26, 10, 28, 14))
113
121
  # This next isn't in the same pattern; it makes a Decimal from a BigNum rather than a String (coverage reasons)
114
122
  @decimal_sub_value = Mod::DecimalSubVal.new(98765432109876543210)
123
+ @guid_sub_value = Mod::GuidSubVal.new(:new)
115
124
 
116
125
  # Entities identified by Value Type, SubType and Entity-by-value-type instances
117
126
  @test_by_int = Mod::TestByInt.new(2)
@@ -125,6 +134,7 @@ describe "An instance of every type of ObjectType" do
125
134
  @test_by_date_time = Mod::TestByDateTime.new([[2008,04,28,10,28,15]])
126
135
  #@test_by_date_time = Mod::TestByDateTime.new(DateTime.new(2008,04,28,10,28,15))
127
136
  @test_by_decimal = Mod::TestByDecimal.new('98765432109876543210')
137
+ @test_by_guid = Mod::TestByGuid.new('01234567-89ab-cdef-0123-456789abcdef')
128
138
 
129
139
  @test_by_int_sub = Mod::TestByIntSub.new(2)
130
140
  @test_by_real_sub = Mod::TestByRealSub.new(5.0)
@@ -134,6 +144,7 @@ describe "An instance of every type of ObjectType" do
134
144
  @test_by_date_sub = Mod::TestByDateSub.new(Date.new(2008,04,27))
135
145
  @test_by_date_time_sub = Mod::TestByDateTimeSub.new(2008,04,29,10,28,15)
136
146
  @test_by_decimal_sub = Mod::TestByDecimalSub.new('98765432109876543210')
147
+ @test_by_guid_sub = Mod::TestByGuidSub.new('01234567-89ab-cdef-0123-456789abcdef')
137
148
 
138
149
  @test_by_int_entity = Mod::TestByIntEntity.new(@test_by_int)
139
150
  @test_by_real_entity = Mod::TestByRealEntity.new(@test_by_real)
@@ -143,6 +154,7 @@ describe "An instance of every type of ObjectType" do
143
154
  @test_by_date_entity = Mod::TestByDateEntity.new(@test_by_date)
144
155
  @test_by_date_time_entity = Mod::TestByDateTimeEntity.new(@test_by_date_time)
145
156
  @test_by_decimal_entity = Mod::TestByDecimalEntity.new(@test_by_decimal)
157
+ @test_by_guid_entity = Mod::TestByGuidEntity.new(@test_by_guid)
146
158
 
147
159
  # Entity subtypes
148
160
  @test_sub_by_int = Mod::TestSubByInt.new(2)
@@ -153,45 +165,54 @@ describe "An instance of every type of ObjectType" do
153
165
  @test_sub_by_date = Mod::TestSubByDate.new(Date.new(2008,04,28))
154
166
  @test_sub_by_date_time = Mod::TestSubByDateTime.new(2008,04,28,10,28,15)
155
167
  @test_sub_by_decimal = Mod::TestSubByDecimal.new('98765432109876543210')
168
+ @test_sub_by_guid = Mod::TestSubByGuid.new('01234567-89ab-cdef-0123-456789abcdef')
156
169
 
157
170
  # These arrays get zipped together in various ways. Keep them aligned.
158
171
  @values = [
159
172
  @int, @real, @auto_counter, @new_auto_counter,
160
- @string, @date, @date_time, @decimal
173
+ @string, @date, @date_time, @decimal, @guid
161
174
  ]
162
175
  @classes = [
163
176
  Int, Real, AutoCounter, AutoCounter,
164
- String, Date, DateTime, Decimal
177
+ String, Date, DateTime, Decimal, Guid
165
178
  ]
166
179
  @value_types = [
167
180
  Mod::IntVal, Mod::RealVal, Mod::AutoCounterVal, Mod::AutoCounterVal,
168
181
  Mod::StringVal, Mod::DateVal, Mod::DateTimeVal, Mod::DecimalVal,
182
+ Mod::GuidVal,
169
183
  Mod::IntSubVal, Mod::RealSubVal, Mod::AutoCounterSubVal, Mod::AutoCounterSubVal,
170
184
  Mod::StringSubVal, Mod::DateSubVal, Mod::DateTimeSubVal, Mod::DecimalSubVal,
185
+ Mod::GuidSubVal,
171
186
  ]
172
187
  @value_instances = [
173
188
  @int_value, @real_value, @auto_counter_value, @new_auto_counter_value,
174
- @string_value, @date_value, @date_time_value, @decimal_value,
189
+ @string_value, @date_value, @date_time_value, @decimal_value, @guid_value,
175
190
  @int_sub_value, @real_sub_value, @auto_counter_sub_value, @auto_counter_sub_value_new,
176
- @string_sub_value, @date_sub_value, @date_time_sub_value, @decimal_sub_value,
191
+ @string_sub_value, @date_sub_value, @date_time_sub_value, @decimal_sub_value, @guid_sub_value,
177
192
  @int_value, @real_value, @auto_counter_value, @new_auto_counter_value,
178
- @string_value, @date_value, @date_time_value, @decimal_value,
193
+ @string_value, @date_value, @date_time_value, @decimal_value, @guid_value,
179
194
  ]
180
195
  @entity_types = [
181
196
  Mod::TestByInt, Mod::TestByReal, Mod::TestByAutoCounter, Mod::TestByAutoCounter,
182
197
  Mod::TestByString, Mod::TestByDate, Mod::TestByDateTime, Mod::TestByDecimal,
198
+ Mod::TestByGuid,
183
199
  Mod::TestByIntSub, Mod::TestByRealSub, Mod::TestByAutoCounterSub, Mod::TestByAutoCounterSub,
184
200
  Mod::TestByStringSub, Mod::TestByDateSub, Mod::TestByDateTimeSub, Mod::TestByDecimalSub,
201
+ Mod::TestByGuidSub,
185
202
  Mod::TestSubByInt, Mod::TestSubByReal, Mod::TestSubByAutoCounter, Mod::TestSubByAutoCounter,
186
203
  Mod::TestSubByString, Mod::TestSubByDate, Mod::TestSubByDateTime, Mod::TestByDecimalEntity,
204
+ Mod::TestByGuidEntity,
187
205
  ]
188
206
  @entities = [
189
207
  @test_by_int, @test_by_real, @test_by_auto_counter, @test_by_auto_counter_new,
190
208
  @test_by_string, @test_by_date, @test_by_date_time, @test_by_decimal,
209
+ @test_by_guid,
191
210
  @test_by_int_sub, @test_by_real_sub, @test_by_auto_counter_sub, @test_by_auto_counter_new_sub,
192
211
  @test_by_string_sub, @test_by_date_sub, @test_by_date_time_sub, @test_by_decimal_sub,
212
+ @test_by_guid_sub,
193
213
  @test_sub_by_int, @test_sub_by_real, @test_sub_by_auto_counter, @test_sub_by_auto_counter_new,
194
214
  @test_sub_by_string, @test_sub_by_date, @test_sub_by_date_time, @test_sub_by_decimal,
215
+ @test_sub_by_guid,
195
216
  ]
196
217
  @entities_by_entity = [
197
218
  @test_by_int_entity,
@@ -202,28 +223,35 @@ describe "An instance of every type of ObjectType" do
202
223
  @test_by_date_entity,
203
224
  @test_by_date_time_entity,
204
225
  @test_by_decimal_entity,
226
+ @test_by_guid_entity,
205
227
  ]
206
228
  @entities_by_entity_types = [
207
229
  Mod::TestByIntEntity, Mod::TestByRealEntity, Mod::TestByAutoCounterEntity, Mod::TestByAutoCounterEntity,
208
230
  Mod::TestByStringEntity, Mod::TestByDateEntity, Mod::TestByDateTimeEntity, Mod::TestByDecimalEntity,
231
+ Mod::TestByGuidEntity,
209
232
  ]
210
233
  @test_role_names = [
211
234
  :int_value, :real_value, :auto_counter_value, :auto_counter_value,
212
235
  :string_value, :date_value, :date_time_value, :decimal_value,
236
+ :guid_value,
213
237
  :int_sub_value, :real_sub_value, :auto_counter_sub_value, :auto_counter_sub_value,
214
238
  :string_sub_value, :date_sub_value, :date_time_sub_value, :decimal_sub_value,
239
+ :guid_sub_value,
215
240
  :int_value, :real_value, :auto_counter_value, :auto_counter_value,
216
241
  :string_value, :date_value, :date_time_value, :decimal_value,
242
+ :guid_value,
217
243
  ]
218
244
  @role_values = [
219
245
  3, 4.0, 5, 6,
220
246
  "three", Date.new(2008,4,21), DateTime.new(2008,4,22,10,28,16),
221
- '98765432109876543210'
247
+ '98765432109876543210',
248
+ '01234567-89ab-cdef-0123-456789abcdef'
222
249
  ]
223
250
  @role_alternate_values = [
224
251
  4, 5.0, 6, 7,
225
252
  "four", Date.new(2009,4,21), DateTime.new(2009,4,22,10,28,16),
226
- '98765432109876543211'
253
+ '98765432109876543211',
254
+ '01234567-89ab-cdef-0123-456789abcdef'
227
255
  ]
228
256
  @subtype_role_instances = [
229
257
  Mod::IntSubVal.new(6), Mod::RealSubVal.new(6.0),
@@ -231,6 +259,7 @@ describe "An instance of every type of ObjectType" do
231
259
  Mod::StringSubVal.new("seven"),
232
260
  Mod::DateSubVal.new(2008,4,29), Mod::DateTimeSubVal.new(2008,4,30,10,28,16),
233
261
  Mod::DecimalSubVal.new('98765432109876543210'),
262
+ Mod::DecimalSubVal.new('01234567-89ab-cdef-0123-456789abcdef'),
234
263
  ]
235
264
  end
236
265
 
@@ -3,9 +3,9 @@
3
3
  # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
4
  #
5
5
 
6
- VALUE_TYPES = Int, Real, AutoCounter, String, Date, DateTime, Decimal
7
- RAW_VALUES = [2, 3.0, 4, "5", Date.new(2008, 04, 20), DateTime.new(2008, 04, 20, 10, 28, 14)]
8
- ALT_VALUES = [3, 4.0, 5, "6", Date.new(2009, 04, 20), DateTime.new(2009, 04, 20, 10, 28, 14)]
6
+ VALUE_TYPES = Int, Real, AutoCounter, String, Date, DateTime, Decimal, Guid
7
+ RAW_VALUES = [2, 3.0, 4, "5", Date.new(2008, 04, 20), DateTime.new(2008, 04, 20, 10, 28, 14), '43210.98765', '01234567-89ab-cdef-0123-456789abcdef']
8
+ ALT_VALUES = [3, 4.0, 5, "6", Date.new(2009, 04, 20), DateTime.new(2009, 04, 20, 10, 28, 14), '56789.01234', 'fedcba987654-3210-fedc-ba98-76543210']
9
9
  VALUE_SUB_FOR_VALUE = {}
10
10
  VALUES_FOR_TYPE = VALUE_TYPES.zip(RAW_VALUES, ALT_VALUES).inject({}) do |h, (vt, v1, v2)|
11
11
  next h unless v1 and v2
@@ -186,7 +186,7 @@ describe "Object type role values" do
186
186
  it "should allow nullifying and reassigning a #{object_type_name} entity's identifying role value" do
187
187
  object = @constellation.send(object_type_name, *object_identifying_parameters(object_type_name, values[0]))
188
188
  object.class.identifying_roles.each do |identifying_role|
189
- next if identifying_role.name == :counter
189
+ next if [:counter, :id_guid_val].include?(identifying_role.name)
190
190
  assigned = object.send(:"#{identifying_role.name}=", nil)
191
191
  assigned.should be_nil
192
192
  object.send(:"#{identifying_role.name}=", values[1])
@@ -54,6 +54,48 @@ describe "Roles" do
54
54
  role.counterpart.object_type.should == Mod::Name
55
55
  end
56
56
 
57
+ it "should prevent association of a role name with an object_type from the wrong module" do
58
+ lambda {
59
+ module Mod2
60
+ class Unrelated
61
+ end
62
+ end
63
+
64
+ module Mod
65
+ class Existing1 < String
66
+ value_type
67
+ has_one :unrelated, :class => Mod2::Unrelated
68
+ end
69
+ end
70
+ }.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
71
+ end
72
+
73
+ it "should prevent association of a role name with a non-object_type" do
74
+ lambda {
75
+ module Mod
76
+ class NonObject
77
+ end
78
+ class Existing1 < String
79
+ value_type
80
+ has_one :non_object, :class => NonObject
81
+ end
82
+ end
83
+ }.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
84
+ end
85
+
86
+ it "should prevent association of a role name with an implied non-object_type" do
87
+ lambda {
88
+ module Mod
89
+ class NonObject
90
+ end
91
+ class Existing1 < String
92
+ value_type
93
+ has_one :non_object
94
+ end
95
+ end
96
+ }.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
97
+ end
98
+
57
99
  it "should provide value type metadata" do
58
100
  Mod::Name.length.should == 40
59
101
  Mod::Name.scale.should == 0
@@ -67,6 +67,7 @@ describe "identity" do
67
67
  @p2.should be_nil
68
68
  @c1.Name.values.should =~ [@juliar, @tony]
69
69
  @c1.Name.keys.should =~ [@juliar, @tony]
70
+ pending "This functionality was poorly implemented and has been temporarily switched off"
70
71
  @c1.TFN.keys.should =~ [123]
71
72
  @c1.Person.values.should =~ [@p1, @p3]
72
73
  @c1.Person.keys.should =~ [[@juliar],[@tony]]
@@ -0,0 +1,38 @@
1
+ #
2
+ # ActiveFacts tests: Value instances in the Runtime API
3
+ # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
+ #
5
+ require 'activefacts/api'
6
+
7
+ describe Date do
8
+ it "should construct with no arguments" do
9
+ proc {
10
+ @d = Date.new()
11
+ }.should_not raise_error
12
+ @d.year.should == -4712
13
+ end
14
+
15
+ it "should construct with a nil argument" do
16
+ proc {
17
+ @d = Date.new(nil)
18
+ }.should_not raise_error
19
+ @d.year.should == -4712
20
+ end
21
+
22
+ it "should construct with a full arguments" do
23
+ proc {
24
+ @d = Date.civil(2012, 10, 31)
25
+ }.should_not raise_error
26
+ @d.to_s.should == "2012-10-31"
27
+ end
28
+
29
+ =begin
30
+ it "should be encodable in JSON" do
31
+ proc {
32
+ @d = Date.new(2012, 10, 31)
33
+ @d.to_json.should == "REVISIT"
34
+ }.should_not raise_error
35
+ end
36
+ =end
37
+
38
+ end
@@ -0,0 +1,71 @@
1
+ #
2
+ # ActiveFacts tests: Value instances in the Runtime API
3
+ # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
+ #
5
+
6
+ describe "Guid Value Type instances" do
7
+ before :each do
8
+ Object.send :remove_const, :Mod if Object.const_defined?("Mod")
9
+ module Mod
10
+ class ThingId < Guid
11
+ value_type
12
+ end
13
+ class Thing
14
+ identified_by :thing_id
15
+ one_to_one :thing_id
16
+ end
17
+ class Ordinal < Int
18
+ value_type
19
+ end
20
+ class ThingFacet
21
+ identified_by :thing, :ordinal
22
+ has_one :thing
23
+ has_one :ordinal
24
+ end
25
+ end
26
+ @constellation = ActiveFacts::API::Constellation.new(Mod)
27
+ @thing = Mod::Thing.new(:new)
28
+ @thing_id = Mod::ThingId.new
29
+ end
30
+
31
+ it "should respond to verbalise" do
32
+ @thing_id.respond_to?(:verbalise).should be_true
33
+ end
34
+
35
+ it "should verbalise correctly" do
36
+ @thing_id.verbalise.should =~ /ThingId '[-0-9a-f]{36}'/i
37
+ end
38
+
39
+ it "should respond to constellation" do
40
+ @thing_id.respond_to?(:constellation).should be_true
41
+ end
42
+
43
+ it "should respond to its roles" do
44
+ @thing_id.respond_to?(:thing).should be_true
45
+ end
46
+
47
+ it "should allow prevent invalid role assignment" do
48
+ lambda {
49
+ @thing.thing_id = "foo"
50
+ }.should raise_error
51
+ end
52
+
53
+ it "should allow an existing guid to be re-used" do
54
+ @new_thing = Mod::Thing.new(@thing_id)
55
+ @new_thing.thing_id.should == @thing_id
56
+ end
57
+
58
+ it "should return the ValueType in response to .class()" do
59
+ @thing_id.class.vocabulary.should == Mod
60
+ end
61
+
62
+ it "should allow an existing guid-identified object to be re-used" do
63
+ thing = @constellation.Thing(:new)
64
+ facets = []
65
+ facets << @constellation.ThingFacet(thing, 0)
66
+ facets << @constellation.ThingFacet(thing, 1)
67
+ facets[0].thing.should be_eql(facets[1].thing)
68
+ facets[0].thing.thing_id.should be_eql(facets[1].thing.thing_id)
69
+ end
70
+
71
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activefacts-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-17 00:00:00.000000000 Z
12
+ date: 2012-11-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -59,6 +59,54 @@ dependencies:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: 2.6.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: ruby-debug
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: debugger
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: pry
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
62
110
  - !ruby/object:Gem::Dependency
63
111
  name: rspec
64
112
  requirement: !ruby/object:Gem::Requirement
@@ -159,6 +207,7 @@ files:
159
207
  - lib/activefacts/api/constellation.rb
160
208
  - lib/activefacts/api/entity.rb
161
209
  - lib/activefacts/api/exceptions.rb
210
+ - lib/activefacts/api/guid.rb
162
211
  - lib/activefacts/api/instance.rb
163
212
  - lib/activefacts/api/instance_index.rb
164
213
  - lib/activefacts/api/numeric.rb
@@ -182,6 +231,8 @@ files:
182
231
  - spec/object_type/entity_type/entity_type_spec.rb
183
232
  - spec/object_type/entity_type/multipart_identification_spec.rb
184
233
  - spec/object_type/value_type/autocounter_spec.rb
234
+ - spec/object_type/value_type/date_time_spec.rb
235
+ - spec/object_type/value_type/guid_spec.rb
185
236
  - spec/object_type/value_type/numeric_spec.rb
186
237
  - spec/object_type/value_type/value_type_spec.rb
187
238
  - spec/simplecov_helper.rb
@@ -202,7 +253,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
202
253
  version: '0'
203
254
  segments:
204
255
  - 0
205
- hash: -2189448494771312824
256
+ hash: 1877620921052571193
206
257
  required_rubygems_version: !ruby/object:Gem::Requirement
207
258
  none: false
208
259
  requirements: