hprevalence 0.1.0 → 0.1.1

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.
data/lib/hprevalence.rb CHANGED
@@ -13,15 +13,25 @@ module HPrevalence
13
13
  class EngineBuilder
14
14
 
15
15
  def self.build( target_dir, &system_init )
16
+ ensure_dir( target_dir )
16
17
  system = system_init.call
17
18
  SimpleEngine.new( target_dir, system )
18
19
  end
19
20
 
20
21
  def self.build_transparent( target_dir, &system_init )
22
+ ensure_dir( target_dir )
21
23
  system = system_init.call
22
24
  TransparentEngine.new( target_dir, system )
23
25
  end
24
26
 
27
+ private
28
+
29
+ def self.ensure_dir( dir )
30
+ return if File.exists?( dir )
31
+ require 'fileutils'
32
+ FileUtils.mkdir_p( dir )
33
+ end
34
+
25
35
  end
26
36
 
27
37
  #
@@ -56,7 +66,6 @@ module HPrevalence
56
66
  end
57
67
 
58
68
  #
59
- # Holds only one system
60
69
  #
61
70
  class TransparentEngine < SimpleEngine
62
71
  @@engines = Hash.new()
@@ -70,11 +79,11 @@ module HPrevalence
70
79
 
71
80
  TransparentEngine.register_engine( self )
72
81
 
73
- @proxies = []
82
+ @proxies = Hash.new
74
83
  add_engine_id_method( system )
75
84
  store_manager = TransparentStorageManager.new(self, target_dir)
76
85
  within_engine {
77
- @proxied_system = HPrevalence::Transparent::TransparentProxy.new( system )
86
+ @proxied_system = HPrevalence::Transparent::TransparentProxy.new( system, Guid.from_s('00000000-0000-0000-0000-000000000000') )
78
87
  }
79
88
 
80
89
  super( target_dir, system, store_manager )
@@ -103,17 +112,20 @@ module HPrevalence
103
112
  end
104
113
 
105
114
  def execute_command(command)
106
- super(command)
115
+ begin
116
+ Thread.current[:references] = Hash.new
117
+ super(command)
118
+ ensure
119
+ Thread.current[:references] = nil
120
+ end
107
121
  end
108
122
 
109
123
  def register_proxy(proxy)
110
- # TODO: Synchronization here?
111
- @proxies << proxy
112
- @proxies.length - 1
124
+ @proxies[ proxy.proxy_id.to_s ] = proxy
113
125
  end
114
126
 
115
127
  def proxy_by_id( id, related_symbol = nil, parent_proxy_id = nil )
116
- p = @proxies[ id ]
128
+ p = @proxies[ id.to_s ]
117
129
  return p unless p.nil?
118
130
  if !related_symbol.nil? && !parent_proxy_id.nil?
119
131
  return create_nested_proxy( parent_proxy_id, related_symbol )
@@ -126,12 +138,23 @@ module HPrevalence
126
138
  parent_proxy = proxy_by_id( parent_proxy_id )
127
139
  target = parent_proxy.target
128
140
  nested_target = target.send( related_symbol )
129
- new_proxy = HPrevalence::Transparent::NestedTransparentProxy.new( nested_target, related_symbol, parent_proxy_id )
141
+ new_proxy = HPrevalence::Transparent::NestedTransparentProxy.new(
142
+ nested_target, related_symbol, parent_proxy_id )
130
143
  target._set_proxy( related_symbol, new_proxy )
131
144
  return new_proxy
132
145
  }
133
146
  end
134
147
 
148
+ def create_result_proxy( target )
149
+ @proxies_lock.synchronize {
150
+ # parent_proxy = proxy_by_id( parent_proxy_id )
151
+ # target = parent_proxy.target
152
+ # result = target.send( related_symbol, *args )
153
+ new_proxy = HPrevalence::Transparent::TransparentProxy.new( target )
154
+ return new_proxy
155
+ }
156
+ end
157
+
135
158
  def within_engine()
136
159
  begin
137
160
  Thread.current[:engine] = self
@@ -143,9 +166,9 @@ module HPrevalence
143
166
 
144
167
  def restore(proxy)
145
168
  proxy.engine_id = @engine_id
146
- p = proxy_by_id(proxy.proxy_id)
169
+ p = proxy_by_id( proxy.proxy_id )
147
170
  if (p.nil?)
148
- proxy.proxy_id = register_proxy(proxy)
171
+ register_proxy(proxy)
149
172
  p = proxy
150
173
  end
151
174
  p
@@ -157,6 +180,12 @@ module HPrevalence
157
180
  }
158
181
  end
159
182
 
183
+ def self.create_result_proxy( target, engine_id )
184
+ within_engine( engine_id ) { |engine|
185
+ engine.create_result_proxy( target )
186
+ }
187
+ end
188
+
160
189
  def self.within_engine( engine_id )
161
190
  engine = @@engines[ engine_id ]
162
191
  raise 'Engine not found' if engine.nil?
@@ -202,13 +231,10 @@ module HPrevalence
202
231
  system.instance_eval {
203
232
  @engine_id = temp_id
204
233
  }
205
- # (class << system; self;end).class_eval do
206
- # define_method(:_engine_id) { @engine_id }
207
- # end
208
234
  end
209
-
210
235
  end
211
236
 
237
+ #
212
238
  class PrevalenceService
213
239
  attr_reader :engine
214
240
 
data/lib/transparent.rb CHANGED
@@ -7,10 +7,35 @@ module HPrevalence
7
7
 
8
8
  def self.included(type)
9
9
  class << type
10
- def attr_proxy( *symbols )
10
+ def method_added(symbol)
11
+ self.instance_eval do
12
+ @readonly_attributes ||= []
13
+ hierarchy = self
14
+ while hierarchy = hierarchy.superclass
15
+ if (hierarchy.instance_eval {instance_variables.include? '@readonly_attributes'})
16
+ @readonly_attributes |= hierarchy.instance_eval {@readonly_attributes}
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def attr_proxy_attribute( *symbols )
11
23
  @proxied_attributes ||= []
12
24
  symbols.each do |symbol|
13
- @proxied_attributes << symbol
25
+ self.instance_eval {
26
+ @proxied_attributes ||= []
27
+ @proxied_attributes << symbol
28
+ }
29
+ end
30
+ end
31
+
32
+ def attr_proxy_method( *symbols )
33
+ @proxied_attributes ||= []
34
+ symbols.each do |symbol|
35
+ self.instance_eval {
36
+ @proxied_methods ||= []
37
+ @proxied_methods << symbol
38
+ }
14
39
  end
15
40
  end
16
41
 
@@ -28,14 +53,20 @@ module HPrevalence
28
53
  def _read_only_attributes()
29
54
  self.class.instance_eval { @readonly_attributes ||= [] }
30
55
  end
31
-
56
+
32
57
  def _proxied_attributes()
33
58
  self.class.instance_eval { @proxied_attributes ||= [] }
34
59
  end
35
60
 
61
+ def _proxied_methods()
62
+ self.class.instance_eval { @proxied_methods ||= [] }
63
+ end
64
+
36
65
  def _should_proxy( symbol )
37
66
  if _proxied_attributes().include?( symbol )
38
67
  return true if _symbol2proxy(symbol).nil?
68
+ elsif _proxied_methods().include?( symbol )
69
+ return true
39
70
  end
40
71
  false
41
72
  end
@@ -46,7 +77,7 @@ module HPrevalence
46
77
  @symbol2proxy[symbol]
47
78
  }
48
79
  end
49
-
80
+
50
81
  def _set_proxy( symbol, proxy )
51
82
  self.instance_eval {
52
83
  @symbol2proxy ||= {}
@@ -59,14 +90,14 @@ module HPrevalence
59
90
  class AutomaticCommand
60
91
 
61
92
  def initialize( proxy_id, symbol, *args )
62
- @proxy_id, @symbol, @args = proxy_id, symbol, *args
93
+ @proxy_id, @symbol, @args = proxy_id, symbol, args
63
94
  end
64
95
 
65
96
  def execute(system)
66
97
  TransparentEngine.current() { |engine|
67
98
  proxy = engine.proxy_by_id(@proxy_id)
68
99
  raise 'Could not obtain proxy' if proxy.nil?
69
- return proxy.send(@symbol, *arguments)
100
+ return proxy.target.send(@symbol, *arguments)
70
101
  }
71
102
  end
72
103
 
@@ -77,7 +108,7 @@ module HPrevalence
77
108
  end
78
109
 
79
110
  end
80
-
111
+
81
112
  class NestedAutomaticCommand < AutomaticCommand
82
113
 
83
114
  attr_reader :related_symbol, :parent_proxy_id
@@ -93,7 +124,7 @@ module HPrevalence
93
124
  TransparentEngine.current() { |engine|
94
125
  proxy = engine.proxy_by_id(@proxy_id, @related_symbol, @parent_proxy_id)
95
126
  raise 'Could not obtain proxy' if proxy.nil?
96
- return proxy.send(@symbol, *arguments)
127
+ return proxy.target.send(@symbol, *arguments)
97
128
  }
98
129
  end
99
130
  end
@@ -101,14 +132,15 @@ module HPrevalence
101
132
  class TransparentProxy
102
133
  attr_accessor :target, :proxy_id, :engine_id
103
134
 
104
- def initialize(target)
135
+ def initialize(target, new_id = Guid.new)
105
136
  raise 'A proxy must have a target' if target.nil?
106
137
  raise 'Strange. A proxy is supposed to exist within an engine' unless Thread.current[:engine]
138
+ @proxy_id = new_id
107
139
  @engine_id = Thread.current[:engine].engine_id
108
- @proxy_id = Thread.current[:engine].register_proxy(self)
109
- # puts "New proxy with id #{@proxy_id.to_s} for #{target.class.to_s}"
140
+ Thread.current[:engine].register_proxy(self)
110
141
  @target = target
111
142
  @is_custom = target.kind_of?(CustomBehavior)
143
+ # puts "New proxy with id #{@proxy_id.to_s} for #{target.class.to_s}"
112
144
  end
113
145
 
114
146
  def method_missing(symbol, *args, &block)
@@ -117,16 +149,15 @@ module HPrevalence
117
149
 
118
150
  if (@is_custom)
119
151
  if (@target._read_only_attributes.include?(symbol) )
120
- return @target.send(symbol, *args)
121
- elsif (@target._should_proxy(symbol) )
152
+ return @target.send(symbol, *args, &block)
153
+ elsif (args.length == 0 && @target._should_proxy(symbol) )
154
+ # Attribute being accessed
122
155
  return TransparentEngine.create_nested_proxy( @proxy_id, symbol, @engine_id )
123
- # nested_target = @target.send(symbol, *args)
124
- # return nil if nested_target.nil?
125
- # TransparentEngine.within_engine( @engine_id ) { |engine|
126
- # new_proxy = TransparentProxy.new( nested_target )
127
- # @target._set_proxy( symbol, new_proxy )
128
- # return new_proxy
129
- # }
156
+ elsif (args.length != 0 && @target._should_proxy(symbol) )
157
+ # Method being accessed
158
+ result = proceed(symbol, *args, &block)
159
+ return TransparentEngine.create_result_proxy( result, @engine_id )
160
+ # return TransparentProxy.new( result )
130
161
  else
131
162
  nested_proxy = @target._symbol2proxy(symbol)
132
163
  # Returns the nested proxy associated with this symbol
@@ -138,30 +169,26 @@ module HPrevalence
138
169
  proceed(symbol, *args, &block)
139
170
  end
140
171
 
141
- # Custom marshalling - this adds the internal id (myid) and the system id to a marshall
142
- # of the object we are the proxy for.
143
- # We take care to not marshal the same object twice, so circular references will work.
144
-
145
172
  def _dump(depth)
146
173
  references = Thread.current[:references]
147
174
  if (references)
148
175
  if (references[self])
149
- [@proxy_id.to_s, @engine_id.to_s].pack("A8A40")
176
+ # puts "> serializing placeholder #{@proxy_id.to_s}"
177
+ [@proxy_id.to_s, @engine_id.to_s].pack("A40A40")
150
178
  else
179
+ # puts "> serializing proxy #{@proxy_id.to_s}"
151
180
  references[self] = true
152
- [@proxy_id.to_s, @engine_id.to_s].pack("A8A40") + Marshal.dump(@target, depth)
181
+ [@proxy_id.to_s, @engine_id.to_s].pack("A40A40") + Marshal.dump(@target, depth)
153
182
  end
154
183
  else
155
- [@proxy_id.to_s, @engine_id.to_s].pack("A8A40")
184
+ [@proxy_id.to_s, @engine_id.to_s].pack("A40A40")
156
185
  end
157
186
  end
158
187
 
159
- # Custom marshalling - restore a Prox object.
160
-
161
188
  def TransparentProxy._load(buffer)
162
189
  proxy = TransparentProxy.allocate
163
- list = buffer.unpack("A8A40a*")
164
- proxy.proxy_id = list[0].to_i
190
+ list = buffer.unpack("A40A40a*")
191
+ proxy.proxy_id = Guid.from_s( list[0] )
165
192
  proxy.engine_id = Guid.from_s( list[1] )
166
193
  TransparentEngine.current() { |engine|
167
194
  proxy = engine.restore(proxy)
@@ -193,24 +220,24 @@ module HPrevalence
193
220
  end
194
221
  result
195
222
  end
196
-
223
+
197
224
  end
198
-
225
+
199
226
  class NestedTransparentProxy < TransparentProxy
200
- attr_reader :related_symbol, :parent_proxy_id
227
+ attr_reader :related_symbol, :parent_proxy_id, :args
201
228
 
202
- def initialize(target, symbol, parent_proxy_id)
229
+ def initialize(target, symbol, parent_proxy_id, *args)
203
230
  raise 'A nested-proxy must have a symbol' if symbol.nil?
204
231
  super(target)
205
- @related_symbol, @parent_proxy_id = symbol, parent_proxy_id
232
+ @related_symbol, @parent_proxy_id, @args = symbol, parent_proxy_id, args
206
233
  end
207
-
234
+
208
235
  protected
209
236
 
210
237
  def build_command( symbol, *args )
211
238
  NestedAutomaticCommand.new( @related_symbol, @parent_proxy_id, @proxy_id, symbol, *args )
212
239
  end
213
-
240
+
214
241
  end
215
242
 
216
243
  end
data/rakefile.rb CHANGED
@@ -10,7 +10,7 @@ require 'rake/rdoctask'
10
10
 
11
11
  #task :default => [ :test_units, :test_functional, :appdoc, :stats ]
12
12
  desc "Run all the tests"
13
- task :default => [ :test_units, :package ]
13
+ task :default => [ :test_units ]
14
14
 
15
15
  desc "Run the unit tests in test/unit"
16
16
  Rake::TestTask.new("test_units") { |t|
@@ -19,7 +19,7 @@ Rake::TestTask.new("test_units") { |t|
19
19
  t.verbose = true
20
20
  }
21
21
 
22
- PKG_VERSION = '0.1.0'
22
+ PKG_VERSION = '0.1.1'
23
23
  PKG_FILES = FileList['README', './**/*.rb']
24
24
 
25
25
  spec = Gem::Specification.new do |s|
@@ -1,10 +1,14 @@
1
1
 
2
2
  module AbstractHPrevalenceTestHelper
3
3
 
4
+ def create_dir_name( name )
5
+ current_dir = File.dirname(__FILE__)
6
+ File.join( current_dir, name )
7
+ end
8
+
4
9
  def reset_dir( dir )
5
10
  begin
6
- current_dir = File.dirname(__FILE__)
7
- @target_dir = File.join( current_dir, dir )
11
+ @target_dir = create_dir_name( dir )
8
12
  if File.exist?( @target_dir )
9
13
  Dir.entries( @target_dir ).each do |file|
10
14
  File.delete( File.join(@target_dir,file) ) unless File.directory?( file )
@@ -0,0 +1,96 @@
1
+
2
+ $:.unshift(File.dirname(__FILE__) + "/../lib/")
3
+
4
+ require 'hprevalence'
5
+ require 'transparent'
6
+ require 'abstract_hprevalence_testcase'
7
+ require 'dvd_store_model'
8
+ require 'test/unit'
9
+
10
+ class Item
11
+ attr_accessor :sub_item
12
+
13
+ def initialize( sub )
14
+ @sub_item = sub
15
+ end
16
+ end
17
+
18
+ class SampleDatabase
19
+ include HPrevalence::Transparent::CustomBehavior
20
+
21
+ attr_reader :list
22
+ attr_proxy_attribute :list
23
+ attr_proxy_method :create_item
24
+
25
+ def initialize()
26
+ @list = []
27
+ end
28
+
29
+ def create_item( sub = nil )
30
+ Item.new( sub )
31
+ end
32
+ end
33
+
34
+ class CircularReferenceTest < Test::Unit::TestCase
35
+ include AbstractHPrevalenceTestHelper
36
+
37
+ def setup
38
+ reset_dir 'store/circular_test'
39
+ ensure_dir
40
+ load_engine
41
+ end
42
+
43
+ def teardown
44
+ @engine.close
45
+ end
46
+
47
+ def load_engine
48
+ teardown unless @engine.nil?
49
+
50
+ @engine = HPrevalence::EngineBuilder.build_transparent( @target_dir ) {
51
+ SampleDatabase.new()
52
+ }
53
+
54
+ assert_not_nil @engine
55
+ @system = @engine.system
56
+ assert_not_nil @system
57
+ end
58
+
59
+ def test_simple
60
+ item = @system.create_item()
61
+ @system.list << item
62
+
63
+ load_engine
64
+
65
+ assert_equal 1, @system.list.length
66
+ end
67
+
68
+ def test_circular
69
+ item = @system.create_item()
70
+ item.sub_item = item
71
+
72
+ @system.list << item
73
+
74
+ load_engine
75
+
76
+ assert_equal 1, @system.list.length
77
+ item = @system.list[0]
78
+ assert_equal item, item.sub_item
79
+ end
80
+
81
+ def test_circular_with_snapshot
82
+ item = @system.create_item()
83
+ item.sub_item = item
84
+
85
+ @system.list << item
86
+
87
+ @engine.take_snapshot
88
+ load_engine
89
+
90
+ assert_equal 1, @system.list.length
91
+ item = @system.list[0]
92
+ assert_equal item, item.sub_item
93
+ end
94
+
95
+ end
96
+
@@ -2,6 +2,41 @@ $:.unshift(File.dirname(__FILE__) + "/../lib/")
2
2
 
3
3
  require 'transparent'
4
4
 
5
+ class AbstractCollection
6
+ include Enumerable
7
+ include HPrevalence::Transparent::CustomBehavior
8
+ attr_read_only :each
9
+
10
+ def initialize()
11
+ @list = []
12
+ end
13
+
14
+ def add( item )
15
+ @list << item
16
+ item
17
+ end
18
+
19
+ def each()
20
+ @list.each { |item|
21
+ yield(item)
22
+ }
23
+ end
24
+
25
+ def length
26
+ @list.length
27
+ end
28
+
29
+ end
30
+
31
+ class DvdCollection < AbstractCollection
32
+ # include HPrevalence::Transparent::CustomBehavior
33
+
34
+ def initialize()
35
+ super
36
+ end
37
+
38
+ end
39
+
5
40
  class DvdStore
6
41
  include HPrevalence::Transparent::CustomBehavior
7
42
 
@@ -9,11 +44,12 @@ class DvdStore
9
44
  attr_reader :available_categories
10
45
  attr_reader :customers
11
46
 
12
- attr_proxy :available_items, :available_categories, :customers
47
+ attr_proxy_attribute :available_items, :available_categories, :customers
48
+ attr_proxy_method :create_dvd
13
49
  attr_read_only :total_customers
14
50
 
15
51
  def initialize()
16
- @available_items = []
52
+ @available_items = DvdCollection.new()
17
53
  @available_categories = []
18
54
  @customers = []
19
55
  end
@@ -21,6 +57,10 @@ class DvdStore
21
57
  def total_customers
22
58
  @customers.length
23
59
  end
60
+
61
+ def create_dvd( dvd )
62
+ dvd
63
+ end
24
64
 
25
65
  end
26
66
 
@@ -41,8 +41,11 @@ class NaturalObjectModelTest < Test::Unit::TestCase
41
41
  @system.available_categories << fiction
42
42
  @system.available_categories << comedy
43
43
 
44
- @system.available_items << Dvd.new( 'Fight Club', 22.1, fiction )
45
- @system.available_items << Dvd.new( 'Monty Python and the Holy Grail', 15, comedy )
44
+ dvd1 = @system.create_dvd( Dvd.new( 'Fight Club', 22.1, fiction ) )
45
+ dvd2 = @system.create_dvd( Dvd.new( 'Monty Python and the Holy Grail', 15, comedy ) )
46
+
47
+ @system.available_items.add( dvd1 )
48
+ @system.available_items.add( dvd2 )
46
49
 
47
50
  assert_equal 2, @system.available_items.length
48
51
  assert_equal 2, @system.available_categories.length
@@ -53,6 +56,27 @@ class NaturalObjectModelTest < Test::Unit::TestCase
53
56
  assert_equal 2, @system.available_categories.length
54
57
  end
55
58
 
59
+ def test_read_only_each
60
+ assert_equal 0, @system.total_customers
61
+
62
+ fiction = Category.new('Fiction')
63
+ comedy = Category.new('Comedy')
64
+
65
+ @system.available_categories << fiction
66
+ @system.available_categories << comedy
67
+
68
+ dvd1 = @system.create_dvd( Dvd.new( 'Fight Club', 22.1, fiction ) )
69
+ dvd2 = @system.create_dvd( Dvd.new( 'Monty Python and the Holy Grail', 15, comedy ) )
70
+
71
+ @system.available_items.add( dvd1 )
72
+ @system.available_items.add( dvd2 )
73
+
74
+ @system.available_items.each() do |item|
75
+
76
+ end
77
+
78
+ end
79
+
56
80
  def test_more_engine_loads
57
81
  load_engine
58
82
  assert_equal 0, @system.total_customers
@@ -66,8 +90,8 @@ class NaturalObjectModelTest < Test::Unit::TestCase
66
90
  assert_equal 0, @system.available_items.length
67
91
  assert_equal 2, @system.available_categories.length
68
92
 
69
- @system.available_items << Dvd.new( 'Fight Club', 22.1, fiction )
70
- @system.available_items << Dvd.new( 'Monty Python and the Holy Grail', 15, comedy )
93
+ @system.available_items.add( Dvd.new( 'Fight Club', 22.1, fiction ) )
94
+ @system.available_items.add( Dvd.new( 'Monty Python and the Holy Grail', 15, comedy ) )
71
95
 
72
96
  assert_equal 2, @system.available_items.length
73
97
  assert_equal 2, @system.available_categories.length
@@ -80,8 +104,8 @@ class NaturalObjectModelTest < Test::Unit::TestCase
80
104
  horror = Category.new('Horror')
81
105
  @system.available_categories << horror
82
106
 
83
- @system.available_items << Dvd.new( 'Pet Sematary - 1989', 22.6, horror )
84
- @system.available_items << Dvd.new( 'Falwty Towers - 12 episodes', 40.6, comedy )
107
+ @system.available_items.add( Dvd.new( 'Pet Sematary - 1989', 22.6, horror ) )
108
+ @system.available_items.add( Dvd.new( 'Fawlty Towers - 12 episodes', 40.6, comedy ) )
85
109
 
86
110
  assert_equal 4, @system.available_items.length
87
111
  assert_equal 3, @system.available_categories.length
@@ -102,8 +126,8 @@ class NaturalObjectModelTest < Test::Unit::TestCase
102
126
  @system.available_categories << fiction
103
127
  @system.available_categories << comedy
104
128
 
105
- @system.available_items << Dvd.new( 'Fight Club', 22.1, fiction )
106
- @system.available_items << Dvd.new( 'Monty Python and the Holy Grail', 15, comedy )
129
+ @system.available_items.add( Dvd.new( 'Fight Club', 22.1, fiction ) )
130
+ @system.available_items.add( Dvd.new( 'Monty Python and the Holy Grail', 15, comedy ) )
107
131
 
108
132
  assert_equal 2, @system.available_items.length
109
133
  assert_equal 2, @system.available_categories.length
@@ -0,0 +1,99 @@
1
+ $:.unshift(File.dirname(__FILE__) + "/../lib/")
2
+
3
+ require 'hprevalence'
4
+ require 'transparent'
5
+
6
+ class ModelBase
7
+ include HPrevalence::Transparent::CustomBehavior
8
+ attr_read_only :ident
9
+
10
+ attr_reader :ident
11
+ attr_accessor :name
12
+
13
+ def initialize(name, id_val = name)
14
+ @ident, @name = id_val, name
15
+ end
16
+ end
17
+
18
+ class ModelArrayBase
19
+ include Enumerable
20
+ include HPrevalence::Transparent::CustomBehavior
21
+ attr_read_only :[], :each, :length
22
+
23
+ def initialize()
24
+ @list = []
25
+ end
26
+
27
+ def add( item )
28
+ @list << item
29
+ end
30
+
31
+ def each
32
+ @list.each { |item| yield(item) }
33
+ end
34
+
35
+ def [](index)
36
+ if (index.kind_of?(Integer))
37
+ return @list[index]
38
+ elsif (index.kind_of?(String))
39
+ return find { |item| item.ident == index }
40
+ end
41
+ end
42
+
43
+ def length
44
+ @list.length
45
+ end
46
+
47
+ end
48
+
49
+ class User < ModelBase
50
+ attr_reader :password
51
+
52
+ def initialize(name, password)
53
+ super(name)
54
+ @password = password
55
+ end
56
+ end
57
+
58
+ class Project < ModelBase
59
+ attr_reader :owner
60
+
61
+ def initialize(name, idVal, owner)
62
+ super(name, idVal)
63
+ @owner = owner
64
+ end
65
+ end
66
+
67
+ class UserCollection < ModelArrayBase
68
+ def initialize()
69
+ super
70
+ end
71
+ end
72
+
73
+ class ProjectCollection < ModelArrayBase
74
+ def initialize()
75
+ super
76
+ end
77
+ end
78
+
79
+ class ApplicationDatabase
80
+ include HPrevalence::Transparent::CustomBehavior
81
+
82
+ attr_reader :users, :projects
83
+ attr_proxy_attribute :users, :projects
84
+ attr_proxy_method :create_user, :create_project
85
+
86
+ def initialize
87
+ @users = UserCollection.new()
88
+ @projects = ProjectCollection.new()
89
+ end
90
+
91
+ def create_user( login, pass )
92
+ User.new( login, pass )
93
+ end
94
+
95
+ def create_project( name, id, user )
96
+ Project.new( name, id, user )
97
+ end
98
+
99
+ end
@@ -0,0 +1,54 @@
1
+
2
+ $:.unshift(File.dirname(__FILE__) + "/../lib/")
3
+
4
+ require 'hprevalence'
5
+ require 'transparent'
6
+ require 'abstract_hprevalence_testcase'
7
+ require 'project_model'
8
+ require 'test/unit'
9
+
10
+ class RestoringTest < Test::Unit::TestCase
11
+ include AbstractHPrevalenceTestHelper
12
+
13
+ def setup
14
+ @target_dir = create_dir_name('store/fixed')
15
+ load_engine
16
+ end
17
+
18
+ def teardown
19
+ @engine.close
20
+ end
21
+
22
+ def load_engine
23
+ teardown unless @engine.nil?
24
+
25
+ @engine = HPrevalence::EngineBuilder.build_transparent( @target_dir ) {
26
+ ApplicationDatabase.new()
27
+ }
28
+
29
+ assert_not_nil @engine
30
+ @system = @engine.system
31
+ assert_not_nil @system
32
+ end
33
+
34
+ def test_a
35
+ teardown
36
+ reset_dir 'store/fixed'
37
+ setup
38
+
39
+ user = @system.create_user( "test", "test" )
40
+ @system.users.add( user ) unless @system.users.length != 0
41
+
42
+ project = @system.create_project( 'cas', 'Castle', user )
43
+ @system.projects.add( project )
44
+
45
+ end
46
+
47
+ def atest_aaa
48
+
49
+ assert_equal 1, @system.users.length
50
+ assert_equal 1, @system.projects.length
51
+
52
+ end
53
+
54
+ end
data/test/task_model.rb CHANGED
@@ -22,6 +22,10 @@ class TaskDatabase
22
22
  def add_task( task )
23
23
  @tasks << task
24
24
  end
25
+
26
+ def add( name, contents )
27
+ add_task( Task.new(name, contents) )
28
+ end
25
29
 
26
30
  def remove_task_by_name( name )
27
31
  @tasks.delete_if { |task|
@@ -5,6 +5,16 @@ require 'transparent'
5
5
  require 'abstract_hprevalence_testcase'
6
6
  require 'task_model'
7
7
  require 'test/unit'
8
+ require 'guid'
9
+
10
+ class FakeProxy
11
+ attr_reader :proxy_id
12
+
13
+ def initialize()
14
+ @proxy_id = Guid.new
15
+ end
16
+
17
+ end
8
18
 
9
19
  class TransparentTest < Test::Unit::TestCase
10
20
  include AbstractHPrevalenceTestHelper
@@ -32,17 +42,14 @@ class TransparentTest < Test::Unit::TestCase
32
42
  end
33
43
 
34
44
  def test_proxy_registration
35
- fake_proxy1 = ""
36
- fake_proxy2 = 10
45
+ fake_proxy1 = FakeProxy.new()
46
+ fake_proxy2 = FakeProxy.new()
37
47
 
38
- proxy_id1 = @engine.register_proxy( fake_proxy1 )
39
- proxy_id2 = @engine.register_proxy( fake_proxy2 )
48
+ @engine.register_proxy( fake_proxy1 )
49
+ @engine.register_proxy( fake_proxy2 )
40
50
 
41
- assert_not_nil proxy_id1
42
- assert_not_nil proxy_id2
43
-
44
- assert_equal fake_proxy1, @engine.proxy_by_id( proxy_id1 )
45
- assert_equal fake_proxy2, @engine.proxy_by_id( proxy_id2 )
51
+ assert_equal fake_proxy1, @engine.proxy_by_id( fake_proxy1.proxy_id )
52
+ assert_equal fake_proxy2, @engine.proxy_by_id( fake_proxy2.proxy_id )
46
53
  end
47
54
 
48
55
  def test_simple_case
@@ -91,5 +98,18 @@ class TransparentTest < Test::Unit::TestCase
91
98
 
92
99
  assert_equal 3, @system.tasks.length
93
100
  end
101
+
102
+ def test_recursive_invocations
103
+ assert_equal 0, @system.tasks.length
104
+ @system.add( 'first', 'content' )
105
+ @system.add( 'second', 'content' )
106
+ assert_equal 2, @system.tasks.length
107
+
108
+ @engine.take_snapshot
109
+
110
+ load_engine
111
+
112
+ assert_equal 2, @system.tasks.length
113
+ end
94
114
 
95
115
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.1
3
3
  specification_version: 1
4
4
  name: hprevalence
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2004-10-24
6
+ version: 0.1.1
7
+ date: 2004-10-27
8
8
  summary: Ruby based prevalence engine.
9
9
  require_paths:
10
10
  - lib
@@ -33,15 +33,17 @@ files:
33
33
  - "./lib/transparent.rb"
34
34
  - "./lib/internal/command_logger.rb"
35
35
  - "./lib/internal/iomanager.rb"
36
- - "./lib/internal/object_graph.rb"
37
36
  - "./lib/internal/serializer.rb"
38
37
  - "./lib/internal/store_manager.rb"
39
38
  - "./test/abstract_hprevalence_testcase.rb"
39
+ - "./test/circular_reference_test.rb"
40
40
  - "./test/command_logger_test.rb"
41
41
  - "./test/default_model_serializer_test.rb"
42
42
  - "./test/dvd_store_model.rb"
43
43
  - "./test/file_io_manager_test.rb"
44
44
  - "./test/natural_object_model_test.rb"
45
+ - "./test/project_model.rb"
46
+ - "./test/restoring_test.rb"
45
47
  - "./test/simple_engine_test.rb"
46
48
  - "./test/task_model.rb"
47
49
  - "./test/transparent_module_test.rb"
@@ -1,68 +0,0 @@
1
-
2
- class ObjectGraph
3
-
4
- def initialize()
5
- @root = nil
6
- @registry = Hash.new()
7
- end
8
-
9
- def self.build( node )
10
- graph = ObjectGraph.new()
11
- graph.root = node
12
- graph
13
- end
14
-
15
- def root=( node )
16
- @root = GraphItem.new( self, node )
17
- end
18
-
19
- def root
20
- @root.object
21
- end
22
-
23
- def object_reference( var )
24
- graph_item = @registry[ var ]
25
- if (graph_item.nil?)
26
- graph_item = GraphItem.new( self, var )
27
- @registry[ var ] = graph_item
28
- end
29
- graph_item
30
- end
31
-
32
- end
33
-
34
- class GraphItem
35
-
36
- def initialize( graph, node )
37
- @instance_vars = Hash.new
38
- @node_type = node.class
39
-
40
- node.instance_variables.each do |var|
41
- name = var.slice(1, var.length - 1)
42
- @instance_vars[ name ] = graph.object_reference( node.instance_eval(var) )
43
- end
44
- end
45
-
46
- def object
47
- obj = @node_type.allocate
48
- restore_instance_vars obj
49
- obj
50
- end
51
-
52
- protected
53
-
54
- def restore_instance_vars(obj)
55
- @instance_vars.each do |name, value|
56
-
57
- var = value.object
58
-
59
- setter = name + "="
60
- if obj.respond_to?(setter)
61
- obj.__send__(setter, var)
62
- else
63
- obj.instance_eval("@#{ name } = var")
64
- end
65
- end
66
- end
67
-
68
- end