Permalink
Browse files

Implements flat hash class.

Makes hash traversing function such as #each work with a single argument
instead of 2.
  • Loading branch information...
1 parent a53891e commit ab679d4edbc9e32b39dfd4cbfc416c1698df813a @kouno committed Sep 5, 2012
View
@@ -32,6 +32,7 @@
require 'activefacts/api/support' # General support code and core patches
require 'activefacts/api/vocabulary' # A Ruby module may become a Vocabulary
+require 'activefacts/api/flat_hash' # Common behavior shared by RoleValues and InstanceIndex
require 'activefacts/api/instance_index' # The index used by a constellation to record every instance
require 'activefacts/api/comparable_hash_key' # The keys used by RoleValues and InstanceIndex
require 'activefacts/api/constellation' # A Constellation is a query result or fact population
@@ -0,0 +1,43 @@
+#
+# ActiveFacts Runtime API
+# InstanceIndex class
+#
+# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
+#
+
+module ActiveFacts
+ module API
+ # FlatHash implements two different behaviors.
+ #
+ # It uses comparable hash keys which allows comparison of nil values and
+ # it makes traversing methods of the hash work like an array.
+ #
+ # Example:
+ # flat_hash.each { |v| p v }
+ # # instead of
+ # hash.each { |k, v| p v }
+ # # while keeping behaviors such as
+ # flat_hash['hello'] = 'world'
+ module FlatHash
+ def []=(key, value)
+ @hash[ComparableHashKey.new(key)] = value
+ end
+
+ def [](key)
+ @hash[ComparableHashKey.new(key)]
+ end
+
+ def keys
+ @hash.keys.map { |key| key.value }
+ end
+
+ def each(&block)
+ if block.arity < 2
+ @hash.each { |_,v| block.call(v) }
+ else
+ @hash.each(&block)
+ end
+ end
+ end
+ end
+end
@@ -17,8 +17,8 @@ module API
#
class InstanceIndex
extend Forwardable
- def_delegators :@hash, :size, :empty?, :each, :map,
- :detect, :values, :detect, :delete_if
+ include FlatHash
+ def_delegators :@hash, :size, :empty?, :map, :values, :delete_if
def initialize(constellation, klass)
@constellation = constellation
@@ -52,20 +52,7 @@ def include?(*args)
end
def detect &b
- r = @hash.detect &b
- r ? r[1] : nil
- end
-
- def []=(key, value) #:nodoc:
- @hash[ComparableHashKey.new(key)] = value
- end
-
- def [](key)
- @hash[ComparableHashKey.new(key)]
- end
-
- def keys
- @hash.keys.map { |key| key.value }
+ @hash.detect(&b)[1]
end
def delete(key)
@@ -11,67 +11,56 @@ module API
class RoleValues #:nodoc:
include Enumerable
+ include FlatHash
extend Forwardable
- def_delegators :@a, :each, :size, :empty?, :values
+ def_delegators :@hash, :size, :empty?, :values
def initialize
- @a = RBTree.new
+ @hash = RBTree.new
end
- def +(role_values)
- if role_values.is_a?(RoleValues)
- values + role_values.values
+ def +(object)
+ if object.is_a?(RoleValues)
+ values + object.values
else
- values + role_values
+ values + object
end
end
- def -(a)
- clone = Hash[values]
- if self[a]
- clone.delete(ComparableHashKey.new(a))
+ def -(object)
+ clone = Hash.new(values)
+ if self[object]
+ clone.delete(ComparableHashKey.new(object))
end
clone.values
end
def single
- size > 1 ? nil : @a.first[1]
+ size > 1 ? nil : @hash.first[1]
end
def update(old, value)
delete(old) if old
self[value] = value if value
end
- def []=(key, value) #:nodoc:
- @a[ComparableHashKey.new(key)] = value
- end
-
- def [](key)
- @a[ComparableHashKey.new(key)]
- end
-
def to_a
values
end
def include?(key)
- @a.has_key?(ComparableHashKey.new(key))
- end
-
- def keys
- @a.keys.map { |key| key.value }
+ @hash.has_key?(ComparableHashKey.new(key))
end
def delete(value)
- if @a.has_value?(value)
- @a.delete(@a.index(value))
+ if @hash.has_value?(value)
+ @hash.delete(@hash.index(value))
end
end
def verbalise
- "[#{@a.values.map(&:verbalise).join(", ")}]"
+ "[#{@hash.values.map(&:verbalise).join(", ")}]"
end
end
end
@@ -228,13 +228,13 @@ class Mod::Bar; end
it "should support each" do
baz = @constellation.Name("baz")
count = 0
- @constellation.Name.each { |_, _| count += 1 }
+ @constellation.Name.each { |_| count += 1 }
count.should == 1
end
it "should support detect" do
baz = @constellation.Name("baz")
- @constellation.Name.detect { |_, _| true }.should be_true
+ @constellation.Name.detect { |_| true }.should be_true
end
end
@@ -1,29 +1,36 @@
-describe ActiveFacts::API::ComparableHashKey do
+#
+# ActiveFacts tests: Roles of object_type classes in the Runtime API
+# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
+#
+
+include ActiveFacts::API
+
+describe ComparableHashKey do
it "should be negative for ['a'] <=> ['b']" do
- vt1 = ActiveFacts::API::ComparableHashKey.new(['a'])
- vt2 = ActiveFacts::API::ComparableHashKey.new(['b'])
+ vt1 = ComparableHashKey.new(['a'])
+ vt2 = ComparableHashKey.new(['b'])
vt1.<=>(vt2).should == -1
end
it "should be equal for ['a'] <=> ['a']" do
- vt1 = ActiveFacts::API::ComparableHashKey.new(['a'])
- vt2 = ActiveFacts::API::ComparableHashKey.new(['a'])
+ vt1 = ComparableHashKey.new(['a'])
+ vt2 = ComparableHashKey.new(['a'])
vt1.<=>(vt2).should == 0
end
it "should be negative for ['b'] <=> ['a']" do
- vt1 = ActiveFacts::API::ComparableHashKey.new(['b'])
- vt2 = ActiveFacts::API::ComparableHashKey.new(['a'])
+ vt1 = ComparableHashKey.new(['b'])
+ vt2 = ComparableHashKey.new(['a'])
vt1.<=>(vt2).should == 1
end
it "should fall back on string comparison with nil values" do
- vt1 = ActiveFacts::API::ComparableHashKey.new([nil])
- vt2 = ActiveFacts::API::ComparableHashKey.new(['a'])
+ vt1 = ComparableHashKey.new([nil])
+ vt2 = ComparableHashKey.new(['a'])
vt1.<=>(vt2).should == 1
- vt1 = ActiveFacts::API::ComparableHashKey.new([nil])
- vt2 = ActiveFacts::API::ComparableHashKey.new([1])
+ vt1 = ComparableHashKey.new([nil])
+ vt2 = ComparableHashKey.new([1])
vt1.<=>(vt2).should == 1
end
end
@@ -63,4 +63,12 @@ class EntityC < EntityB
@constellation.EntityC[%w{abc}].should == @c
end
end
+
+ describe 'Enumerable implementation' do
+ it 'should have an arity of 1 for #each' do
+ @constellation.EntityA.each do |*args|
+ args.size.should == 1
+ end
+ end
+ end
end
@@ -386,22 +386,31 @@ def object_identifying_parameters object_type_name, value
it "should support each" do
count = 0
- @role_values.each { |_, _| count += 1 }
+ @role_values.each { |_| count += 1 }
count.should == 1
end
+ it 'should have an arity of 1 for #each' do
+ @role_values.each do |*args|
+ args.size.should == 1
+ end
+ end
+
it "should support detect" do
@role_values.detect { |rv| true }.should be_true
end
+ it "should have an arity of 1 for #detect" do
+ @role_values.detect do |*args|
+ args.size.should == 1
+ end
+ end
+
it "should verbalise" do
@role_values.verbalise.should =~ /Octopus.*Zero '0'/
end
-
end
end
-
end
-
end
end

0 comments on commit ab679d4

Please sign in to comment.