chassis_repo 0.1.0
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/.gitignore +47 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +22 -0
- data/README.md +118 -0
- data/Rakefile +34 -0
- data/chassis_repo.gemspec +33 -0
- data/examples/maglev_repo.rb +56 -0
- data/examples/repo.rb +40 -0
- data/lib/chassis.rb +34 -0
- data/lib/chassis/array_utils.rb +8 -0
- data/lib/chassis/core_ext/array.rb +5 -0
- data/lib/chassis/core_ext/hash.rb +5 -0
- data/lib/chassis/core_ext/string.rb +13 -0
- data/lib/chassis/delegate.rb +29 -0
- data/lib/chassis/error.rb +7 -0
- data/lib/chassis/hash_utils.rb +16 -0
- data/lib/chassis/initializable.rb +3 -0
- data/lib/chassis/logger.rb +8 -0
- data/lib/chassis/persistence.rb +84 -0
- data/lib/chassis/repo.rb +71 -0
- data/lib/chassis/repo/base_repo.rb +99 -0
- data/lib/chassis/repo/delegation.rb +82 -0
- data/lib/chassis/repo/maglev_repo.rb +51 -0
- data/lib/chassis/repo/memory_repo.rb +7 -0
- data/lib/chassis/repo/null_repo.rb +64 -0
- data/lib/chassis/repo/record_map.rb +44 -0
- data/lib/chassis/string_utils.rb +50 -0
- data/lib/chassis/version.rb +3 -0
- data/test/array_utils_test.rb +23 -0
- data/test/chassis_test.rb +7 -0
- data/test/core_ext/array_test.rb +8 -0
- data/test/core_ext/hash_test.rb +8 -0
- data/test/core_ext/string_test.rb +16 -0
- data/test/delegate_test.rb +41 -0
- data/test/error_test.rb +12 -0
- data/test/hash_utils_test.rb +17 -0
- data/test/initializable_test.rb +7 -0
- data/test/logger_test.rb +43 -0
- data/test/persistence_test.rb +112 -0
- data/test/repo/delegation_test.rb +100 -0
- data/test/repo/maglev_repo_test.rb +52 -0
- data/test/repo/memory_repo_test.rb +25 -0
- data/test/repo/null_repo_test.rb +56 -0
- data/test/repo/repo_tests.rb +120 -0
- data/test/repo_test.rb +76 -0
- data/test/string_utils_test.rb +21 -0
- data/test/test_helper.rb +13 -0
- metadata +274 -0
data/.gitignore
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Vagrant #
|
2
|
+
###################
|
3
|
+
.vagrant
|
4
|
+
|
5
|
+
# Compiled source #
|
6
|
+
###################
|
7
|
+
*.com
|
8
|
+
*.class
|
9
|
+
*.dll
|
10
|
+
*.exe
|
11
|
+
*.o
|
12
|
+
*.so
|
13
|
+
|
14
|
+
# Packages #
|
15
|
+
############
|
16
|
+
# it's better to unpack these files and commit the raw source
|
17
|
+
# git has its own built in compression methods
|
18
|
+
*.7z
|
19
|
+
*.dmg
|
20
|
+
*.gz
|
21
|
+
*.iso
|
22
|
+
*.jar
|
23
|
+
*.rar
|
24
|
+
*.tar
|
25
|
+
*.zip
|
26
|
+
|
27
|
+
# Logs and databases #
|
28
|
+
######################
|
29
|
+
*.log
|
30
|
+
*.sql
|
31
|
+
*.sqlite
|
32
|
+
|
33
|
+
# OS generated files #
|
34
|
+
######################
|
35
|
+
.DS_Store
|
36
|
+
.DS_Store?
|
37
|
+
._*
|
38
|
+
.Spotlight-V100
|
39
|
+
.Trashes
|
40
|
+
ehthumbs.db
|
41
|
+
Thumbs.db
|
42
|
+
|
43
|
+
nsqd.*.dat
|
44
|
+
|
45
|
+
# Rubygems #
|
46
|
+
############
|
47
|
+
pkg
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
chassis (0.1.0)
|
5
|
+
interchange
|
6
|
+
lift
|
7
|
+
logger-better
|
8
|
+
prox
|
9
|
+
tnt
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: http://rubygems.org/
|
13
|
+
specs:
|
14
|
+
ansi (1.4.3)
|
15
|
+
builder (3.2.2)
|
16
|
+
interchange (0.1.0)
|
17
|
+
lift (0.1.0)
|
18
|
+
logger-better (0.2.1)
|
19
|
+
metaclass (0.0.4)
|
20
|
+
minitest (5.4.2)
|
21
|
+
minitest-reporters (1.0.7)
|
22
|
+
ansi
|
23
|
+
builder
|
24
|
+
minitest (>= 5.0)
|
25
|
+
ruby-progressbar
|
26
|
+
mocha (1.1.0)
|
27
|
+
metaclass (~> 0.0.1)
|
28
|
+
prox (0.0.1)
|
29
|
+
rake (10.4.2)
|
30
|
+
ruby-progressbar (1.7.0)
|
31
|
+
tnt (0.1.0)
|
32
|
+
|
33
|
+
PLATFORMS
|
34
|
+
ruby
|
35
|
+
|
36
|
+
DEPENDENCIES
|
37
|
+
bundler
|
38
|
+
chassis!
|
39
|
+
minitest (= 5.4.2)
|
40
|
+
minitest-reporters
|
41
|
+
mocha
|
42
|
+
rake
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 ahawkins
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# ChassisRepo
|
2
|
+
|
3
|
+
ChassisRepo is the repo part of the [Chassis project](https://github.com/ahawkins/chassis) which will be used for MagLev.
|
4
|
+
|
5
|
+
## Support Libraries
|
6
|
+
|
7
|
+
Chassis is implemented with help from a few smaller libraries. A
|
8
|
+
unified interface if you do not want to know about such things.
|
9
|
+
|
10
|
+
* Errors with [TNT](https://github.com/ahawkins/tnt)
|
11
|
+
* Object initialization with [Lift](https://github.com/ahawkins/lift)
|
12
|
+
* Interchangeable objects with [Interchange](https://github.com/ahawkins/interchange)
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'chassis_repo'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install chassis_repo
|
27
|
+
|
28
|
+
|
29
|
+
## Data Access
|
30
|
+
|
31
|
+
Chassis includes a
|
32
|
+
[repository](http://martinfowler.com/eaaCatalog/repository.html) using
|
33
|
+
the query pattern as well. The repository pattern is perfect because
|
34
|
+
it does not require knowledge about your persistence layer. It is the
|
35
|
+
access layer. A null, in-memory, and Redis adapter are included. You
|
36
|
+
can subclass these adapters to make your own.
|
37
|
+
`Chassis::Repo::Delegation` can be included in other classes to
|
38
|
+
delegate to the repository.
|
39
|
+
|
40
|
+
Here's an example:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
class CustomerRepo
|
44
|
+
extend Chassis::Repo::Delegation
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
Now there are CRUD methods available on `CustomerRepo` that delegate
|
49
|
+
to the repository for `Customer` objects. `Chassis::Persistence` can
|
50
|
+
be included in any object. It will make the object compatible with
|
51
|
+
the matching repo.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class Customer
|
55
|
+
include Chassis::Persistence
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Now `Customer` responds to `id`, `save`, and `repo`. `repo` looks for
|
60
|
+
a repository class matching the class name (e.g. `CustomerRepo`).
|
61
|
+
Override as you see if.
|
62
|
+
|
63
|
+
More on my blog
|
64
|
+
[here](http://hawkins.io/2014/01/pesistence_with_repository_and_query_patterns/).
|
65
|
+
|
66
|
+
|
67
|
+
## Chassis::DirtySession
|
68
|
+
|
69
|
+
A proxy object used to track assignments. Wrap an object in a dirty
|
70
|
+
session to see what changed and what it changed to.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
Person = Struct.new :name
|
74
|
+
|
75
|
+
adam = Person.new 'adam'
|
76
|
+
|
77
|
+
session = Chassis::DirtySession.new adam
|
78
|
+
session.clean? # => true
|
79
|
+
session.dirty? # => false
|
80
|
+
|
81
|
+
session.name = 'Adman'
|
82
|
+
|
83
|
+
session.dirty? # => true
|
84
|
+
session.clean? # => false
|
85
|
+
|
86
|
+
session.named_changed? # => true
|
87
|
+
session.changed # => set of values changed
|
88
|
+
session.new_values # => { name: 'Adman' }
|
89
|
+
session.original_values # => { name: 'adam' }
|
90
|
+
|
91
|
+
session.reset! # reset everything back to normal
|
92
|
+
```
|
93
|
+
|
94
|
+
## Chassis::Logger
|
95
|
+
|
96
|
+
Chassis includes the `logger-better` gem to refine the standard
|
97
|
+
library logger. `Chassis::Logger` default the `logdev` argument to
|
98
|
+
`Chassis.stream`. This gives a unified place to assign all output.
|
99
|
+
The log level can also be controlled by the `LOG_LEVEL` environment
|
100
|
+
variable. This makes it possible to restart/boot the application with
|
101
|
+
a new log level without redeploying code.
|
102
|
+
|
103
|
+
## Chassis::Observable
|
104
|
+
|
105
|
+
A very simple implementation of the observer pattern. It is different
|
106
|
+
from the standard library implementation for two reasons:
|
107
|
+
|
108
|
+
* you don't need to call `changed` for `notify_observers` to work.
|
109
|
+
* `notify_obsevers` includes `self` as first argument to all observers
|
110
|
+
* there is only the `add_observer` method.
|
111
|
+
|
112
|
+
## Contributing
|
113
|
+
|
114
|
+
1. Fork it
|
115
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
116
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
117
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
118
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require "rake/testtask"
|
5
|
+
require "stringio"
|
6
|
+
|
7
|
+
def capture_stdout
|
8
|
+
out = StringIO.new
|
9
|
+
$stdout = out
|
10
|
+
yield
|
11
|
+
return out
|
12
|
+
ensure
|
13
|
+
$stdout = STDOUT
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Run examples"
|
17
|
+
task :examples do
|
18
|
+
root = File.dirname __FILE__
|
19
|
+
Dir["#{root}/examples/*.rb"].each do |example|
|
20
|
+
capture_stdout do
|
21
|
+
require example
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
namespace :test do
|
27
|
+
Rake::TestTask.new(:all) do |t|
|
28
|
+
t.test_files = FileList['test/**/*_test.rb']
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
task test: ["test:all", "examples"]
|
33
|
+
|
34
|
+
task default: :test
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "chassis/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "chassis_repo"
|
8
|
+
spec.version = Chassis::VERSION
|
9
|
+
spec.authors = ["ahawkins"]
|
10
|
+
spec.email = ["adam@hawkins.io"]
|
11
|
+
spec.description = %q{A collection of modules and helpers for building mantainable Ruby applications}
|
12
|
+
spec.summary = %q{}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "interchange"
|
22
|
+
spec.add_dependency "tnt"
|
23
|
+
spec.add_dependency "lift"
|
24
|
+
|
25
|
+
spec.add_dependency "prox"
|
26
|
+
spec.add_dependency "logger-better"
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler"
|
29
|
+
spec.add_development_dependency "rake"
|
30
|
+
spec.add_development_dependency "mocha"
|
31
|
+
spec.add_development_dependency "minitest", "= 5.4.2"
|
32
|
+
spec.add_development_dependency "minitest-reporters"
|
33
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative '../lib/chassis'
|
2
|
+
|
3
|
+
Maglev.abort
|
4
|
+
|
5
|
+
ROOT_KEY = :chassis_example
|
6
|
+
Maglev[ROOT_KEY] = {}
|
7
|
+
Maglev.commit
|
8
|
+
|
9
|
+
Chassis.repo.register :maglev, Chassis::MaglevRepo.new(Maglev[ROOT_KEY])
|
10
|
+
Chassis.repo.use :maglev
|
11
|
+
|
12
|
+
class Post
|
13
|
+
attr_accessor :id, :title, :text
|
14
|
+
end
|
15
|
+
Post.maglev_persistable
|
16
|
+
|
17
|
+
repo = Chassis.repo
|
18
|
+
|
19
|
+
puts repo.empty? Post #=> true
|
20
|
+
|
21
|
+
post = Post.new
|
22
|
+
post.title = 'Such Repos'
|
23
|
+
post.text = 'Very wow. Much design.'
|
24
|
+
|
25
|
+
repo.save post
|
26
|
+
|
27
|
+
puts post.id #=> 1
|
28
|
+
|
29
|
+
found_post = repo.find Post, post.id
|
30
|
+
found_post == post #=> true (no difference between objects in memory)
|
31
|
+
|
32
|
+
post.title = 'Such updates'
|
33
|
+
post.text = 'Very easy. Wow'
|
34
|
+
|
35
|
+
repo.save post
|
36
|
+
|
37
|
+
repo.find(Post, post.id).text #=> 'Very easy. Wow.'
|
38
|
+
|
39
|
+
class PostRepo
|
40
|
+
extend Chassis::Repo::Delegation
|
41
|
+
end
|
42
|
+
|
43
|
+
post = Post.new
|
44
|
+
post.title = 'Such Repos'
|
45
|
+
post.text = 'Very wow. Much design.'
|
46
|
+
|
47
|
+
PostRepo.save post
|
48
|
+
|
49
|
+
post = PostRepo.find post.id
|
50
|
+
post.text #=> 'Very Easy. Wow'
|
51
|
+
|
52
|
+
PostRepo.all #=> [post]
|
53
|
+
# etc
|
54
|
+
|
55
|
+
PostRepo.delete post
|
56
|
+
PostRepo.empty? #=> true
|
data/examples/repo.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'chassis'
|
2
|
+
|
3
|
+
class Post
|
4
|
+
attr_accessor :id, :title, :text
|
5
|
+
end
|
6
|
+
|
7
|
+
repo = Chassis::Repo.default
|
8
|
+
|
9
|
+
puts repo.empty? Post #=> true
|
10
|
+
|
11
|
+
post = Post.new
|
12
|
+
post.title = 'Such Repos'
|
13
|
+
post.text = 'Very wow. Much design.'
|
14
|
+
|
15
|
+
repo.save post
|
16
|
+
|
17
|
+
puts post.id #=> 1
|
18
|
+
|
19
|
+
found_post = repo.find Post, post.id
|
20
|
+
found_post == post #=> true (no difference between objects in memory)
|
21
|
+
|
22
|
+
post.title = 'Such updates'
|
23
|
+
post.text = 'Very easy. Wow'
|
24
|
+
|
25
|
+
repo.save post
|
26
|
+
|
27
|
+
repo.find(Post, post.id).text #=> 'Very easy. Wow.'
|
28
|
+
|
29
|
+
class PostRepo
|
30
|
+
extend Chassis::Repo::Delegation
|
31
|
+
end
|
32
|
+
|
33
|
+
post = PostRepo.find post.id
|
34
|
+
post.text #=> 'Very Easy. Wow'
|
35
|
+
|
36
|
+
PostRepo.all #=> [post]
|
37
|
+
# etc
|
38
|
+
|
39
|
+
PostRepo.delete post
|
40
|
+
PostRepo.empty? #=> true
|
data/lib/chassis.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'interchange'
|
4
|
+
require 'tnt'
|
5
|
+
require 'lift'
|
6
|
+
require 'logger-better'
|
7
|
+
require 'prox'
|
8
|
+
|
9
|
+
module Chassis
|
10
|
+
Proxy = Prox
|
11
|
+
class << self
|
12
|
+
def stream
|
13
|
+
@stream
|
14
|
+
end
|
15
|
+
|
16
|
+
def stream=(stream)
|
17
|
+
@stream = stream
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require_relative 'chassis/hash_utils'
|
23
|
+
require_relative 'chassis/string_utils'
|
24
|
+
require_relative 'chassis/array_utils'
|
25
|
+
require_relative 'chassis/error'
|
26
|
+
require_relative 'chassis/logger'
|
27
|
+
require_relative 'chassis/persistence'
|
28
|
+
require_relative 'chassis/initializable'
|
29
|
+
require_relative 'chassis/repo'
|
30
|
+
require_relative 'chassis/delegate'
|
31
|
+
|
32
|
+
Chassis.repo.register :memory, Chassis::MemoryRepo.new
|
33
|
+
Chassis.repo.register :null, Chassis::NullRepo.new
|
34
|
+
Chassis.repo.use :memory
|