hprevalence 0.1.0 → 0.1.1

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