terrestrial 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/Gemfile.lock +29 -24
  4. data/README.md +35 -17
  5. data/Rakefile +4 -9
  6. data/TODO.md +25 -18
  7. data/bin/test +31 -0
  8. data/docs/domain_object_contract.md +50 -0
  9. data/features/env.rb +4 -6
  10. data/features/example.feature +28 -28
  11. data/features/step_definitions/example_steps.rb +2 -2
  12. data/lib/terrestrial/adapters/memory_adapter.rb +241 -0
  13. data/lib/terrestrial/collection_mutability_proxy.rb +7 -2
  14. data/lib/terrestrial/dirty_map.rb +5 -0
  15. data/lib/terrestrial/error.rb +69 -0
  16. data/lib/terrestrial/graph_loader.rb +58 -35
  17. data/lib/terrestrial/graph_serializer.rb +37 -30
  18. data/lib/terrestrial/inspection_string.rb +19 -0
  19. data/lib/terrestrial/lazy_collection.rb +2 -2
  20. data/lib/terrestrial/lazy_object_proxy.rb +1 -1
  21. data/lib/terrestrial/many_to_one_association.rb +17 -11
  22. data/lib/terrestrial/public_conveniencies.rb +125 -95
  23. data/lib/terrestrial/relation_mapping.rb +30 -0
  24. data/lib/terrestrial/{mapper_facade.rb → relational_store.rb} +11 -1
  25. data/lib/terrestrial/version.rb +1 -1
  26. data/spec/config_override_spec.rb +10 -14
  27. data/spec/custom_serializers_spec.rb +4 -6
  28. data/spec/deletion_spec.rb +12 -14
  29. data/spec/error_handling/factory_error_handling_spec.rb +61 -0
  30. data/spec/error_handling/serialization_error_spec.rb +50 -0
  31. data/spec/error_handling/upsert_error_spec.rb +132 -0
  32. data/spec/graph_persistence_spec.rb +80 -24
  33. data/spec/graph_traversal_spec.rb +14 -6
  34. data/spec/new_graph_persistence_spec.rb +43 -9
  35. data/spec/object_identity_spec.rb +5 -7
  36. data/spec/ordered_association_spec.rb +4 -6
  37. data/spec/predefined_queries_spec.rb +4 -6
  38. data/spec/querying_spec.rb +4 -12
  39. data/spec/readme_examples_spec.rb +3 -6
  40. data/spec/{persistence_efficiency_spec.rb → sequel_query_efficiency_spec.rb} +101 -19
  41. data/spec/spec_helper.rb +24 -2
  42. data/spec/support/memory_adapter_test_support.rb +21 -0
  43. data/spec/support/{mapper_setup.rb → object_store_setup.rb} +5 -5
  44. data/spec/support/seed_data_setup.rb +3 -1
  45. data/spec/support/sequel_test_support.rb +58 -25
  46. data/spec/{sequel_mapper → terrestrial}/abstract_record_spec.rb +0 -0
  47. data/spec/{sequel_mapper → terrestrial}/collection_mutability_proxy_spec.rb +0 -0
  48. data/spec/{sequel_mapper → terrestrial}/deleted_record_spec.rb +0 -0
  49. data/spec/{sequel_mapper → terrestrial}/dirty_map_spec.rb +38 -6
  50. data/spec/{sequel_mapper → terrestrial}/lazy_collection_spec.rb +2 -3
  51. data/spec/{sequel_mapper → terrestrial}/lazy_object_proxy_spec.rb +0 -0
  52. data/spec/{sequel_mapper → terrestrial}/public_conveniencies_spec.rb +12 -7
  53. data/spec/{sequel_mapper → terrestrial}/upserted_record_spec.rb +0 -0
  54. data/{sequel_mapper.gemspec → terrestrial.gemspec} +3 -3
  55. metadata +47 -39
  56. data/lib/terrestrial/short_inspection_string.rb +0 -18
  57. data/spec/proxying_spec.rb +0 -88
  58. data/spec/support/mock_sequel.rb +0 -193
  59. data/spec/support/sequel_persistence_setup.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ba5176dafbe142a9b5f25e00902eec58bd5b858
4
- data.tar.gz: 8674e2b27c6548db3d39b05cd095c6c4d5b9a132
3
+ metadata.gz: c61b139216aa29d6468f16cabdbb135d7c68cbc1
4
+ data.tar.gz: ab6960d54b3c7546f8d95a6e337efddaef166a7f
5
5
  SHA512:
6
- metadata.gz: fb86ee61ccd132a3b1bcaa99b0ab225e59b387cd80c1425d09e847c5f5d52b48610287ae95039d249f8d366fc13abc2045d9ba213eeb963a694f11fb3a068ec0
7
- data.tar.gz: 96c6cfc35fdeba513882de149e1dc751bd6c20628a2743555d1be451b637745dc5ba690c3bcf9db0ac4a7b2a5d52a830d6d9ab8efa8086f89451d2b2ad2ed333
6
+ metadata.gz: b9a11c083365c86dce49908720970407824645d40802fb5adbfd9d9b7adb8fd22f4a2b539e35edd4d630be0881413f3b0ee5063b3a20011707b33edc0687d72d
7
+ data.tar.gz: 7e3a194ff7a687b28fdf62ba993af5b83d5e4294c439d14cce8489f8f2439eadc8684842cfc557a642574076b831e6a5e6eb94347e5ee53079b41793c3349348
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.3
1
+ 2.3.1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- terrestrial (0.0.3)
4
+ terrestrial (0.3.0)
5
5
  activesupport (~> 4.0)
6
6
  fetchable (~> 1.0)
7
7
  sequel (~> 4.16)
@@ -9,49 +9,54 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- activesupport (4.2.4)
12
+ activesupport (4.2.7.1)
13
13
  i18n (~> 0.7)
14
14
  json (~> 1.7, >= 1.7.7)
15
15
  minitest (~> 5.1)
16
16
  thread_safe (~> 0.3, >= 0.3.4)
17
17
  tzinfo (~> 1.1)
18
18
  builder (3.2.2)
19
- coderay (1.1.0)
20
- cucumber (1.3.20)
19
+ coderay (1.1.1)
20
+ cucumber (2.4.0)
21
21
  builder (>= 2.1.2)
22
+ cucumber-core (~> 1.5.0)
23
+ cucumber-wire (~> 0.0.1)
22
24
  diff-lcs (>= 1.1.3)
23
- gherkin (~> 2.12)
25
+ gherkin (~> 4.0)
24
26
  multi_json (>= 1.7.5, < 2.0)
25
27
  multi_test (>= 0.1.2)
28
+ cucumber-core (1.5.0)
29
+ gherkin (~> 4.0)
30
+ cucumber-wire (0.0.1)
26
31
  diff-lcs (1.2.5)
27
32
  fetchable (1.0.0)
28
- gherkin (2.12.2)
29
- multi_json (~> 1.3)
33
+ gherkin (4.0.0)
30
34
  i18n (0.7.0)
31
35
  json (1.8.3)
32
36
  method_source (0.8.2)
33
- minitest (5.8.3)
34
- multi_json (1.11.1)
37
+ minitest (5.9.1)
38
+ multi_json (1.12.1)
35
39
  multi_test (0.1.2)
36
40
  pg (0.17.1)
37
- pry (0.10.1)
41
+ pry (0.10.4)
38
42
  coderay (~> 1.1.0)
39
43
  method_source (~> 0.8.1)
40
44
  slop (~> 3.4)
41
- rake (10.1.0)
42
- rspec (3.1.0)
43
- rspec-core (~> 3.1.0)
44
- rspec-expectations (~> 3.1.0)
45
- rspec-mocks (~> 3.1.0)
46
- rspec-core (3.1.7)
47
- rspec-support (~> 3.1.0)
48
- rspec-expectations (3.1.2)
45
+ rake (10.5.0)
46
+ rspec (3.5.0)
47
+ rspec-core (~> 3.5.0)
48
+ rspec-expectations (~> 3.5.0)
49
+ rspec-mocks (~> 3.5.0)
50
+ rspec-core (3.5.3)
51
+ rspec-support (~> 3.5.0)
52
+ rspec-expectations (3.5.0)
49
53
  diff-lcs (>= 1.2.0, < 2.0)
50
- rspec-support (~> 3.1.0)
51
- rspec-mocks (3.1.3)
52
- rspec-support (~> 3.1.0)
53
- rspec-support (3.1.2)
54
- sequel (4.26.0)
54
+ rspec-support (~> 3.5.0)
55
+ rspec-mocks (3.5.0)
56
+ diff-lcs (>= 1.2.0, < 2.0)
57
+ rspec-support (~> 3.5.0)
58
+ rspec-support (3.5.0)
59
+ sequel (4.39.0)
55
60
  slop (3.6.0)
56
61
  thread_safe (0.3.5)
57
62
  tzinfo (1.2.2)
@@ -70,4 +75,4 @@ DEPENDENCIES
70
75
  terrestrial!
71
76
 
72
77
  BUNDLED WITH
73
- 1.10.6
78
+ 1.12.5
data/README.md CHANGED
@@ -4,22 +4,27 @@
4
4
 
5
5
  * A Ruby ORM that enables DDD and clean architectural styles.
6
6
  * Persists plain objects while supporting arbitrarily deeply nested / circular associations
7
- * Provides excellent database and query building support courtesy of [Sequel library](https://github.com/jeremyevans/sequel)
7
+ * Provides excellent database and query building support courtesy of the [Sequel library](https://github.com/jeremyevans/sequel)
8
8
 
9
9
  Terrestrial is a new, currently experimental [data mapper](http://martinfowler.com/eaaCatalog/dataMapper.html) ORM implementation for Ruby.
10
10
 
11
11
  The aim is to provide a convenient way to query and persist graphs of Ruby objects (think models with associations), while keeping those object completely isolated and decoupled from the database.
12
12
 
13
13
  In contrast to Ruby's many [active record](http://martinfowler.com/eaaCatalog/activeRecord.html) implementations, domain objects require no special inherited or mixed in behavior in order to be persisted.
14
+ In fact Terrestrial has no specific requirements for domain objects at all.
15
+ While there is a simple default, `.new` and `#to_h`, you may define arbitrary
16
+ functions (per mapping) and expose no reader methods at all.
14
17
 
15
18
  ## Features
16
19
 
20
+ * Absolute minimum coupling between domain and persistence
21
+ * Persistence of plain or arbitrary objects
17
22
  * Associations (belongs_to, has_many, has_many_through)
18
23
  * Automatic 'convention over configuration' that is fully customizable
19
- * Lazy loading for database read efficiency
24
+ * Lazy loading of associations
25
+ * Optional eager loading to avoid the `n + 1` query problem
20
26
  * Dirty tracking for database write efficiency
21
27
  * Predefined queries, scopes or subsets
22
- * Eager loading to avoid the `n + 1` query problem
23
28
 
24
29
  There are some [conspicuous missing features](https://github.com/bestie/terrestrial/blob/master/MissingFeatures.md)
25
30
  that you may want to read more about. If you want to contribute to solving any
@@ -69,30 +74,34 @@ code of conduct first.
69
74
  ## This is kept separate from your domain models as knowledge of the schema
70
75
  ## is required to wire them up.
71
76
 
72
- USER_MAPPER_CONFIG = Terrestrial.config(DB)
77
+ MAPPINGS = Terrestrial.config(DB)
73
78
  .setup_mapping(:users) { |users|
79
+ users.class(User) # Specify a class and the constructor will be used
74
80
  users.has_many(:posts, foreign_key: :author_id)
75
81
  }
76
82
  .setup_mapping(:posts) { |posts|
83
+ # To avoid directly specifiying a class, a factory function can be used instead
84
+ posts.factory(->(attrs) { Post.new(attrs) })
77
85
  posts.belongs_to(:author, mapping_name: :users)
78
86
  posts.has_many_through(:categories)
79
87
  }
80
88
  .setup_mapping(:categories) { |categories|
89
+ categories.class(Category)
81
90
  categories.has_many_through(:posts)
82
91
  }
83
92
 
84
- # 4. Create a mapper by combining a connection and a configuration
93
+ # 4. Create an object store by combining a connection and a configuration
85
94
 
86
- USER_MAPPER = Terrestrial.mapper(
95
+ OBJECT_STORE = Terrestrial.object_store(
87
96
  datastore: DB,
88
- config: USER_MAPPER_CONFIG,
89
- name: :users,
97
+ mappings: MAPPINGS,
90
98
  )
91
99
 
92
- ## You are not limted to one mapper configuration or one database connection.
93
- ## To handle complex situations you may create several segregated mappings
94
- ## for your separate aggregate roots, potentially utilising multiple
95
- ## databases and different domain object classes/compositions.
100
+ ## You are not limted to one object store configuration or one database
101
+ ## connection. To handle complex situations you may create several segregated
102
+ ## mappings and object stores for your separate aggregate roots, potentially
103
+ ## utilising multiple databases and different domain object
104
+ ## classes/compositions.
96
105
 
97
106
  # 5. Create some objects
98
107
 
@@ -115,13 +124,13 @@ code of conduct first.
115
124
 
116
125
  # 6. Save them
117
126
 
118
- USER_MAPPER.save(user)
127
+ OBJECT_STORE[:users].save(user)
119
128
 
120
129
  ## Only the (aggregate) root object needs to be passed to the mapper.
121
130
 
122
131
  # 7. Query
123
132
 
124
- user = USER_MAPPER.where(id: "2f0f791c-47cf-4a00-8676-e582075bcd65").first
133
+ user = OBJECT_STORE[:users].where(id: "2f0f791c-47cf-4a00-8676-e582075bcd65").first
125
134
 
126
135
  # => #<struct User
127
136
  # id="2f0f791c-47cf-4a00-8676-e582075bcd65",
@@ -134,7 +143,10 @@ code of conduct first.
134
143
 
135
144
  ## Running the tests
136
145
 
137
- ### Set the following environment variables
146
+ ### ENV vars
147
+
148
+ The test suite expects the following standard Postgres environment variables.
149
+
138
150
  * PGHOST
139
151
  * PGUSER
140
152
  * PGDATABASE
@@ -147,9 +159,15 @@ This will create a database named from the value of `PGDATABASE`
147
159
  $ bundle exec rake db:create
148
160
  ```
149
161
 
150
- ### Run all tests (RSpec and Cucumber)
162
+ ### Run all tests RSpec and Cucumber
163
+
164
+ The RSpec tests run twice, once against Sequel/Postgres and again against
165
+ an in-memory datastore.
166
+
167
+ Cucumber runs only against the Sequel/Postgres backend.
168
+
151
169
  ```
152
- $ bundle exec rake
170
+ $ bin/test
153
171
  ```
154
172
 
155
173
  ### Should anything go awry
data/Rakefile CHANGED
@@ -1,15 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
- require 'rspec/core/rake_task'
4
- require 'cucumber/rake/task'
5
-
6
- RSpec::Core::RakeTask.new
7
- Cucumber::Rake::Task.new
3
+ task :test_suite do
4
+ puts "Run bin/test to run the entire test suite"
5
+ end
8
6
 
9
- task :default => [
10
- :spec,
11
- :cucumber,
12
- ]
7
+ task :default => [:test_suite]
13
8
 
14
9
  require_relative "spec/support/sequel_test_support"
15
10
  require_relative "spec/support/blog_schema"
data/TODO.md CHANGED
@@ -2,29 +2,20 @@
2
2
 
3
3
  In no particular order
4
4
 
5
- ## General
5
+ * User defined default settings for all mappings
6
6
  * Refactor, methods too big, objects missing
7
7
  * Name things better
8
- * Better support swapping out DB for in memory datasets
9
- * `#eager_load!` that raises an error when traversing outside the eagerly
10
- loaded data
8
+ * Full adaptorization of the database, refactor some Sequel specific things
9
+ into the adapter
11
10
 
12
- ## Querying
13
- * Querying API, what would a repository with some arbitrary queries look like?
14
- - e.g. an association on post called `burger_comments` that finds comments
15
- with the word burger in them
16
- * Add other querying methods from association proxies or remove entirely
17
- - Depends on nailing down the querying API
11
+ ## Candidate features to consider
12
+ * Column aliasing
13
+ * Callbacks e.g. after_save, after_insert as functions defined in mapping
14
+ * Database generated IDs and Timestamps (perhaps implemented as callbacks)
18
15
  * When possible optimise blocks given to `AssociationProxy#select` with
19
16
  Sequel's `#where` with block [querying API](http://sequel.jeremyevans.net/rdoc/files/doc/cheat_sheet_rdoc.html#label-AND%2FOR%2FNOT)
20
-
21
- ## Associations
22
- * Read only associations
23
- - Loaded objects would be immutable
24
- - Collection proxy would have no #push or #remove
25
- - Skipped when dumping
26
- * Associations defined with a join
27
- * Composable associations
17
+ * `#eager_load!` that raises an error when traversing outside the eagerly
18
+ loaded data
28
19
 
29
20
  # Hopefully done
30
21
 
@@ -32,10 +23,26 @@ In no particular order
32
23
  * Efficient saving
33
24
  - Part one, if it wasn't loaded it wasn't modified, check identity map
34
25
  - Part two, dirty tracking
26
+ * Support swapping out DB for in memory datasets
35
27
 
36
28
  ## Associations
37
29
  * Eager loading
38
30
 
31
+ ## Querying
32
+ * Querying API, what would a repository with some arbitrary queries look like?
33
+ - e.g. an association on post called `burger_comments` that finds comments
34
+ with the word burger in them
35
+
39
36
  ## Configuration
40
37
  * Automatic config generation based on schema, foreign keys etc
41
38
  * Config to take either a classes or callable factory
39
+
40
+ # Not happening (at least for now)
41
+
42
+ ## Associations
43
+ * Read only associations
44
+ - Loaded objects would be immutable
45
+ - Collection proxy would have no #push or #remove
46
+ - Skipped when dumping
47
+ * Associations defined with a join
48
+ * Composable associations
data/bin/test ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler"
4
+ Bundler.setup
5
+
6
+ ADAPTERS = ["memory", "sequel"]
7
+
8
+ module TerrestrialTesting
9
+ module_function def run_rspec_with_adapter(adapter)
10
+ puts "Running RSpec suite for `#{adapter}` adapter"
11
+ puts "Run following command to replicate"
12
+ puts "ADAPTER=#{adapter} bundle exec rspec"
13
+ puts ""
14
+
15
+ system("ADAPTER=#{adapter} rspec")
16
+ end
17
+
18
+ module_function def run_cucumber
19
+ system("cucumber")
20
+ end
21
+ end
22
+
23
+ exit_successes = ADAPTERS.map do |adapter|
24
+ TerrestrialTesting.run_rspec_with_adapter(adapter)
25
+ end
26
+
27
+ if exit_successes.all?
28
+ exit_successes.push(TerrestrialTesting.run_cucumber)
29
+ end
30
+
31
+ exit exit_successes.all? ? 0 : 1
@@ -0,0 +1,50 @@
1
+ # Domain object contract
2
+
3
+ ## Configurable defaults
4
+
5
+ For saving a new or updating an existing object, Terrestrial assumes that your
6
+ domain objects implement a `#to_h` method that returns a Hash (keyed with
7
+ Symbols) of attributes that can be directly inserted into the database.
8
+
9
+ The `#to_h` interface is common in Ruby, `Struct` and `OpenStruct` both
10
+ implement this behavior as standard.
11
+
12
+ *This is the only method terrestrial will ever call on your objects*
13
+
14
+ For loading previously persisted objects, Terrestrial assumes that your domain
15
+ objects can be instantiated by calling `.new` on the specified or inferred
16
+ class with a Hash (keyed with Symbols) of attributes that match the database
17
+ column names.
18
+
19
+ This attributes Hash into constructor interface is supported by `OpenStruct`
20
+ but not by `Struct`. Terrestrial will treats `Struct` as a special case and
21
+ translates attributes into an ordered array of values. See `Terrestrial::StructAdapter`
22
+
23
+ ## Custom serializers and factories
24
+
25
+ If you prefer Terrestrial not to call any methods on your domain objects this
26
+ is absolutely possible and encouraged.
27
+
28
+ A serializer function should be a lambda like object capable of converting a
29
+ domain object into a Hash (keyed by Symbols) and its persistable values.
30
+
31
+ For the default scenario detailed above Terrestrial generates the following
32
+ lambda.
33
+
34
+ ```ruby
35
+ ->(domain_object) { domain_object.to_h }
36
+ ```
37
+
38
+ A factory lambda will be called with same Hash of Symbol to value as above.
39
+
40
+ The default configuration would generate something like this for a users mapping.
41
+
42
+ ```ruby
43
+ ->(attributes_hash) { User.new(attributes_hash) }
44
+ ```
45
+
46
+ Providing bespoke functions can achieve many goals including:
47
+ * Looser coupling to Terrestrial
48
+ * Translation, modification or decoration of incoming and outgoing data
49
+ * Dynamically select a class (like Rails STI that doesn't necessarily need
50
+ inheritance)
data/features/env.rb CHANGED
@@ -27,7 +27,8 @@ module ExampleRunnerSupport
27
27
  string
28
28
  .strip
29
29
  .gsub(/[\n\s]+/, " ")
30
- .gsub(/\:[0-9a-f]{12}/, ":<<object id removed>>")
30
+ .gsub(/ \>/, ">")
31
+ .gsub(/\:0x[0-9a-f]{14}/, ":<<object id removed>>")
31
32
  end
32
33
 
33
34
  def parse_schema_table(string)
@@ -42,12 +43,9 @@ module ExampleRunnerSupport
42
43
  end
43
44
 
44
45
  module DatabaseSupport
45
- def create_table(name, schema)
46
+ def create_table(name, columns)
46
47
  Terrestrial::SequelTestSupport.create_tables(
47
- tables: {
48
- name => schema,
49
- },
50
- foreign_keys: [],
48
+ name => columns,
51
49
  )
52
50
  end
53
51
  end
@@ -48,28 +48,28 @@ Feature: Basic setup
48
48
  database: ENV.fetch("PGDATABASE"),
49
49
  )
50
50
  """
51
- And the associations are defined in the mapper configuration
52
- """
53
- MAPPINGS_CONFIG = Terrestrial.config(DB)
54
- .setup_mapping(:users) { |users|
55
- users.class(User)
56
- users.has_many(:posts, foreign_key: :author_id)
57
- }
58
- .setup_mapping(:posts) { |posts|
59
- posts.class(Post)
60
- posts.belongs_to(:author, mapping_name: :users)
61
- posts.has_many_through(:categories)
62
- }
63
- .setup_mapping(:categories) { |categories|
64
- categories.class(Category)
65
- categories.has_many_through(:posts)
66
- }
67
- """
68
- And a mapper is instantiated
69
- """
70
- MAPPERS = Terrestrial.mappers(
51
+ And the associations are defined in the configuration
52
+ """
53
+ MAPPINGS = Terrestrial.config(DB)
54
+ .setup_mapping(:users) { |users|
55
+ users.class(User)
56
+ users.has_many(:posts, foreign_key: :author_id)
57
+ }
58
+ .setup_mapping(:posts) { |posts|
59
+ posts.class(Post)
60
+ posts.belongs_to(:author, mapping_name: :users)
61
+ posts.has_many_through(:categories)
62
+ }
63
+ .setup_mapping(:categories) { |categories|
64
+ categories.class(Category)
65
+ categories.has_many_through(:posts)
66
+ }
67
+ """
68
+ And a object store is instantiated
69
+ """
70
+ OBJECT_STORE = Terrestrial.object_store(
71
71
  datastore: DB,
72
- mappings: MAPPINGS_CONFIG,
72
+ mappings: MAPPINGS,
73
73
  )
74
74
  """
75
75
  When a new graph of objects are created
@@ -93,11 +93,11 @@ Feature: Basic setup
93
93
  """
94
94
  And the new graph is saved
95
95
  """
96
- MAPPERS[:users].save(user)
96
+ OBJECT_STORE[:users].save(user)
97
97
  """
98
98
  And the following query is executed
99
99
  """
100
- user = MAPPERS[:users].where(id: "2f0f791c-47cf-4a00-8676-e582075bcd65").first
100
+ user = OBJECT_STORE[:users].where(id: "2f0f791c-47cf-4a00-8676-e582075bcd65").first
101
101
  """
102
102
  Then the persisted user object is returned with lazy associations
103
103
  """
@@ -105,16 +105,16 @@ Feature: Basic setup
105
105
  first_name="Hansel",
106
106
  last_name="Trickett",
107
107
  email="hansel@tricketts.org",
108
- posts=#<Terrestrial::CollectionMutabilityProxy:7fa4817aa148
109
- >>
108
+ posts=#<Terrestrial::CollectionMutabilityProxy:0x007f9d8aa93bf0>
109
+ >
110
110
  """
111
111
  And the user's posts will be loaded once the association proxy receives an Enumerable message
112
112
  """
113
113
  [#<struct Post id="9b75fe2b-d694-4b90-9137-6201d426dda2",
114
- author=#<Terrestrial::LazyObjectProxy:7fec5ac2a5f8 key_fields={:id=>"2f0f791c-47cf-4a00-8676-e582075bcd65"} lazy_object=nil>,
114
+ author=#<Terrestrial::LazyObjectProxy:0x007f81b2b86d30 key_fields={:id=>"2f0f791c-47cf-4a00-8676-e582075bcd65"} lazy_object=nil>,
115
115
  subject="Things that I like",
116
116
  body="I like fish and scratching",
117
117
  created_at=2015-10-03 21:00:00 UTC,
118
- categories=#<Terrestrial::CollectionMutabilityProxy:7fec5ac296f8
119
- >>]
118
+ categories=#<Terrestrial::CollectionMutabilityProxy:0x007f9d8ad88d38>
119
+ >]
120
120
  """