rohbau 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8d05d28272851e7d359b3640cdb9e4a21250f704
4
+ data.tar.gz: 183ca9c967b841d7dc8e4bc6dbdd57e222eab5fc
5
+ SHA512:
6
+ metadata.gz: 9b144522c39a33baa618b912f17e3f9a2a6f743a910194cc052409cd890992a0994eb629da418eb5b5d8cb1816f64159f944c9daada4b55546b1b58f71a86529
7
+ data.tar.gz: 9e6e8cd4e34c668c81172180d3ca99b64af7d5b32e9b1d19a35a72c420e2ad15eda820b0c122f6529bb2a946fe56c0a1d7dbc854bb5b4e458791edfd661e96f7
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,27 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ rvm:
5
+ - ruby-head
6
+ - 2.2
7
+ - 2.1
8
+ - 2.0
9
+ - 1.9.3
10
+ - jruby
11
+ - jruby-head
12
+ - jruby-19mode # JRuby in 1.9 mode
13
+ env:
14
+ global:
15
+ - JRUBY_OPTS='--dev -J-Xmx1024M'
16
+ matrix:
17
+ fast_finish: true
18
+ allow_failures:
19
+ - rvm: ruby-head
20
+ - rvm: jruby-head
21
+ notifications:
22
+ webhooks:
23
+ urls:
24
+ - https://webhooks.gitter.im/e/c6efc69df9417bda7808
25
+ on_success: change # options: [always|never|change] default: always
26
+ on_failure: always # options: [always|never|change] default: always
27
+ on_start: false # default: false
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rohbau.gemspec
4
+ gemspec
5
+
6
+ if ENV['CODECLIMATE_REPO_TOKEN']
7
+ gem "codeclimate-test-reporter", :group => :test, :require => nil
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
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,189 @@
1
+ [github]: https://github.com/neopoly/rohbau
2
+ [doc]: http://rubydoc.info/github/neopoly/rohbau/master/file/README.md
3
+ [gem]: https://rubygems.org/gems/rohbau
4
+ [gem-badge]: https://img.shields.io/gem/v/rohbau.svg
5
+ [travis]: https://travis-ci.org/neopoly/rohbau
6
+ [travis-badge]: https://img.shields.io/travis/neopoly/rohbau.svg?branch=master
7
+ [codeclimate]: https://codeclimate.com/github/neopoly/rohbau
8
+ [codeclimate-climate-badge]: https://img.shields.io/codeclimate/github/neopoly/rohbau.svg
9
+ [codeclimate-coverage-badge]: https://codeclimate.com/github/neopoly/rohbau/badges/coverage.svg
10
+ [inchpages]: https://inch-ci.org/github/neopoly/rohbau
11
+ [inchpages-badge]: https://inch-ci.org/github/neopoly/rohbau.svg?branch=master&style=flat
12
+
13
+ # Rohbau
14
+
15
+ [![Travis][travis-badge]][travis]
16
+ [![Gem Version][gem-badge]][gem]
17
+ [![Code Climate][codeclimate-climate-badge]][codeclimate]
18
+ [![Test Coverage][codeclimate-coverage-badge]][codeclimate]
19
+ [![Inline docs][inchpages-badge]][inchpages]
20
+
21
+ [Gem][gem] |
22
+ [Source][github] |
23
+ [Documentation][doc]
24
+
25
+ ## Description
26
+
27
+ Rohbau provides a set of patterns used in Domain Driven Design.
28
+
29
+ ## Installation
30
+
31
+ Add this line to your application's Gemfile:
32
+
33
+ gem 'rohbau'
34
+
35
+ And then execute:
36
+
37
+ $ bundle
38
+
39
+ Or install it yourself as:
40
+
41
+ $ gem install rohbau
42
+
43
+ ## Usage
44
+
45
+ ### Runtime
46
+
47
+ By instantiation of the `RuntimeLoader`, an instance of the `Runtime`is created and stored as a singleton.
48
+ Internal units of the respective component can access this instance by referring to the `RuntimeLoader`.
49
+ By this a place is made where for example memories for in-memory gateway backend implementations can be stored.
50
+
51
+ #### Examples
52
+
53
+ Inject a user service to your application
54
+
55
+ ```ruby
56
+ require 'rohbau/runtime'
57
+ require 'rohbau/runtime_loader'
58
+
59
+ module MyApplication
60
+ class RuntimeLoader < Rohbau::RuntimeLoader
61
+ def initialize
62
+ super(Runtime)
63
+ end
64
+ end
65
+
66
+ class Runtime < Rohbau::Runtime
67
+ end
68
+ end
69
+
70
+ module UserService
71
+ class RuntimeLoader < Rohbau::RuntimeLoader
72
+ def initialize
73
+ super(Runtime)
74
+ end
75
+ end
76
+
77
+ class Runtime < Rohbau::Runtime
78
+ end
79
+ end
80
+
81
+ # Register user service on my application runtime
82
+ MyApplication::Runtime.register :user_service, UserService::RuntimeLoader
83
+ MyApplication::Runtime.plugins # => {:user_service=>UserService::RuntimeLoader}
84
+
85
+ # Runtimes are not initialized yet
86
+ MyApplication::RuntimeLoader.instance # => nil
87
+ MyApplication::Runtime.plugins[:user_service].instance # => nil
88
+
89
+ # Boot my application runtime
90
+ MyApplication::RuntimeLoader.running? # => false
91
+ MyApplication::RuntimeLoader.new
92
+ MyApplication::RuntimeLoader.running? # => true
93
+
94
+ # Runtimes are initialized
95
+ MyApplication::RuntimeLoader.instance # => #<MyApplication::Runtime:0x00000000f5b8d8 @user_service=UserService::RuntimeLoader>
96
+ MyApplication::Runtime.plugins[:user_service].instance # => #<UserService::Runtime:0x00000000b1ecc0>
97
+
98
+ # Runtimes are singletons
99
+ MyApplication::RuntimeLoader.instance === MyApplication::RuntimeLoader.instance
100
+ MyApplication::Runtime.plugins[:user_service].instance === MyApplication::Runtime.plugins[:user_service].instance
101
+
102
+ # Terminate my application runtime
103
+ MyApplication::RuntimeLoader.terminate
104
+ MyApplication::RuntimeLoader.running? # => false
105
+
106
+ ```
107
+
108
+ ##### Registrar
109
+
110
+ Every injected `RuntimeLoader` knows about it's registrar.
111
+ In the example above `UserService::RuntimeLoader` has been injected to `MyApplication::RuntimeLoader`.
112
+ `UserService::RuntimeLoader.registrar` therefore returns `MyApplication::RuntimeLoader`.
113
+
114
+ ##### List of plugins
115
+
116
+ Accordingly to the sample above `MyApplication::RuntimeLoader` knows about it's registered plugins.
117
+ `MyApplication::RuntimeLoader.plugins` therefore returns `{:user_service => UserService::RuntimeLoader}`.
118
+
119
+ ### ServiceFactory
120
+
121
+ The `ServiceFactory` is considered the authority for retrieval of service instances.
122
+ It follows partly the service locator / registry pattern.
123
+
124
+ #### Examples
125
+
126
+ Register and unregister default service and override with specific service.
127
+
128
+ ```ruby
129
+ require 'rohbau/service_factory'
130
+
131
+ MyServiceFactory = Class.new(Rohbau::ServiceFactory)
132
+
133
+ user_service_1 = Struct.new(:users).new([:alice, :bob])
134
+ user_service_2 = Struct.new(:users).new([:jim, :kate])
135
+
136
+ runtime = Object.new
137
+ registry = MyServiceFactory.new(runtime)
138
+
139
+ MyServiceFactory.register(:user_service) { user_service_1 }
140
+ registry.user_service.users # => [:alice, :bob]
141
+
142
+ MyServiceFactory.register(:user_service) { user_service_2 }
143
+ registry.user_service.users # => [:jim, :kate]
144
+
145
+ MyServiceFactory.unregister(:user_service)
146
+ registry.user_service.users # => [:alice, :bob]
147
+
148
+ MyServiceFactory.unregister(:user_service)
149
+ registry.user_service # => NoMethodError: undefined method `user_service'
150
+
151
+ ```
152
+
153
+ Validate registered dependencies
154
+
155
+ ```ruby
156
+ MyServiceFactory.external_dependencies :user_service
157
+ MyServiceFactory.missing_dependencies # => [:user_service]
158
+ MyServiceFactory.external_dependencies_complied? # => false
159
+
160
+ MyServiceFactory.register(:user_service) { Object.new } # => :user_service
161
+ MyServiceFactory.external_dependencies_complied? # => true
162
+ MyServiceFactory.missing_dependencies # => []
163
+ ```
164
+
165
+ ## Build README
166
+
167
+ Make changes to README.md.template, not to README.md
168
+
169
+ Include examples with
170
+
171
+ ```bash
172
+ include_example example_file_name
173
+ ```
174
+
175
+ Build README.md with
176
+
177
+ ```bash
178
+ ./bin/build_readme
179
+ ```
180
+
181
+ Always commit README.md.template and README.md together.
182
+
183
+ ## Contributing
184
+
185
+ 1. Fork it
186
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
187
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
188
+ 4. Push to the branch (`git push origin my-new-feature`)
189
+ 5. Create new Pull Request
@@ -0,0 +1,119 @@
1
+ [github]: https://github.com/neopoly/rohbau
2
+ [doc]: http://rubydoc.info/github/neopoly/rohbau/master/file/README.md
3
+ [gem]: https://rubygems.org/gems/rohbau
4
+ [gem-badge]: https://img.shields.io/gem/v/rohbau.svg
5
+ [travis]: https://travis-ci.org/neopoly/rohbau
6
+ [travis-badge]: https://img.shields.io/travis/neopoly/rohbau.svg?branch=master
7
+ [codeclimate]: https://codeclimate.com/github/neopoly/rohbau
8
+ [codeclimate-climate-badge]: https://img.shields.io/codeclimate/github/neopoly/rohbau.svg
9
+ [codeclimate-coverage-badge]: https://codeclimate.com/github/neopoly/rohbau/badges/coverage.svg
10
+ [inchpages]: https://inch-ci.org/github/neopoly/rohbau
11
+ [inchpages-badge]: https://inch-ci.org/github/neopoly/rohbau.svg?branch=master&style=flat
12
+
13
+ # Rohbau
14
+
15
+ [![Travis][travis-badge]][travis]
16
+ [![Gem Version][gem-badge]][gem]
17
+ [![Code Climate][codeclimate-climate-badge]][codeclimate]
18
+ [![Test Coverage][codeclimate-coverage-badge]][codeclimate]
19
+ [![Inline docs][inchpages-badge]][inchpages]
20
+
21
+ [Gem][gem] |
22
+ [Source][github] |
23
+ [Documentation][doc]
24
+
25
+ ## Description
26
+
27
+ Rohbau provides a set of patterns used in Domain Driven Design.
28
+
29
+ ## Installation
30
+
31
+ Add this line to your application's Gemfile:
32
+
33
+ gem 'rohbau'
34
+
35
+ And then execute:
36
+
37
+ $ bundle
38
+
39
+ Or install it yourself as:
40
+
41
+ $ gem install rohbau
42
+
43
+ ## Usage
44
+
45
+ ### Runtime
46
+
47
+ By instantiation of the `RuntimeLoader`, an instance of the `Runtime`is created and stored as a singleton.
48
+ Internal units of the respective component can access this instance by referring to the `RuntimeLoader`.
49
+ By this a place is made where for example memories for in-memory gateway backend implementations can be stored.
50
+
51
+ #### Examples
52
+
53
+ Inject a user service to your application
54
+
55
+ ```ruby
56
+ include_example runtime
57
+ ```
58
+
59
+ ##### Registrar
60
+
61
+ Every injected `RuntimeLoader` knows about it's registrar.
62
+ In the example above `UserService::RuntimeLoader` has been injected to `MyApplication::RuntimeLoader`.
63
+ `UserService::RuntimeLoader.registrar` therefore returns `MyApplication::RuntimeLoader`.
64
+
65
+ ##### List of plugins
66
+
67
+ Accordingly to the sample above `MyApplication::RuntimeLoader` knows about it's registered plugins.
68
+ `MyApplication::RuntimeLoader.plugins` therefore returns `{:user_service => UserService::RuntimeLoader}`.
69
+
70
+ ### ServiceFactory
71
+
72
+ The `ServiceFactory` is considered the authority for retrieval of service instances.
73
+ It follows partly the service locator / registry pattern.
74
+
75
+ #### Examples
76
+
77
+ Register and unregister default service and override with specific service.
78
+
79
+ ```ruby
80
+ include_example service_factory
81
+ ```
82
+
83
+ Validate registered dependencies
84
+
85
+ ```ruby
86
+ MyServiceFactory.external_dependencies :user_service
87
+ MyServiceFactory.missing_dependencies # => [:user_service]
88
+ MyServiceFactory.external_dependencies_complied? # => false
89
+
90
+ MyServiceFactory.register(:user_service) { Object.new } # => :user_service
91
+ MyServiceFactory.external_dependencies_complied? # => true
92
+ MyServiceFactory.missing_dependencies # => []
93
+ ```
94
+
95
+ ## Build README
96
+
97
+ Make changes to README.md.template, not to README.md
98
+
99
+ Include examples with
100
+
101
+ ```bash
102
+ include_example example_file_name
103
+ ```
104
+
105
+ Build README.md with
106
+
107
+ ```bash
108
+ ./bin/build_readme
109
+ ```
110
+
111
+ Always commit README.md.template and README.md together.
112
+
113
+ ## Contributing
114
+
115
+ 1. Fork it
116
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
117
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
118
+ 4. Push to the branch (`git push origin my-new-feature`)
119
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.libs += ['spec', 'lib']
6
+ t.test_files = FileList['spec/**/*_spec.rb']
7
+ t.verbose = true
8
+ end
9
+
10
+ task :default => :spec
data/bin/build_readme ADDED
@@ -0,0 +1 @@
1
+ cat README.md.template | etc/build_readme.rb > README.md
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ template = $stdin.read
4
+ examples = template.scan(/include_example (.*)/).flatten
5
+
6
+ examples.each do |example|
7
+ file = "examples/#{example}.rb"
8
+ if File.exists?(file)
9
+ replacement = File.read(file)
10
+ template.gsub!(/include_example #{example}/, replacement)
11
+ end
12
+ end
13
+
14
+ $stdout.print template
@@ -0,0 +1,49 @@
1
+ require 'rohbau/runtime'
2
+ require 'rohbau/runtime_loader'
3
+
4
+ module MyApplication
5
+ class RuntimeLoader < Rohbau::RuntimeLoader
6
+ def initialize
7
+ super(Runtime)
8
+ end
9
+ end
10
+
11
+ class Runtime < Rohbau::Runtime
12
+ end
13
+ end
14
+
15
+ module UserService
16
+ class RuntimeLoader < Rohbau::RuntimeLoader
17
+ def initialize
18
+ super(Runtime)
19
+ end
20
+ end
21
+
22
+ class Runtime < Rohbau::Runtime
23
+ end
24
+ end
25
+
26
+ # Register user service on my application runtime
27
+ MyApplication::Runtime.register :user_service, UserService::RuntimeLoader
28
+ MyApplication::Runtime.plugins # => {:user_service=>UserService::RuntimeLoader}
29
+
30
+ # Runtimes are not initialized yet
31
+ MyApplication::RuntimeLoader.instance # => nil
32
+ MyApplication::Runtime.plugins[:user_service].instance # => nil
33
+
34
+ # Boot my application runtime
35
+ MyApplication::RuntimeLoader.running? # => false
36
+ MyApplication::RuntimeLoader.new
37
+ MyApplication::RuntimeLoader.running? # => true
38
+
39
+ # Runtimes are initialized
40
+ MyApplication::RuntimeLoader.instance # => #<MyApplication::Runtime:0x00000000f5b8d8 @user_service=UserService::RuntimeLoader>
41
+ MyApplication::Runtime.plugins[:user_service].instance # => #<UserService::Runtime:0x00000000b1ecc0>
42
+
43
+ # Runtimes are singletons
44
+ MyApplication::RuntimeLoader.instance === MyApplication::RuntimeLoader.instance
45
+ MyApplication::Runtime.plugins[:user_service].instance === MyApplication::Runtime.plugins[:user_service].instance
46
+
47
+ # Terminate my application runtime
48
+ MyApplication::RuntimeLoader.terminate
49
+ MyApplication::RuntimeLoader.running? # => false
@@ -0,0 +1,21 @@
1
+ require 'rohbau/service_factory'
2
+
3
+ MyServiceFactory = Class.new(Rohbau::ServiceFactory)
4
+
5
+ user_service_1 = Struct.new(:users).new([:alice, :bob])
6
+ user_service_2 = Struct.new(:users).new([:jim, :kate])
7
+
8
+ runtime = Object.new
9
+ registry = MyServiceFactory.new(runtime)
10
+
11
+ MyServiceFactory.register(:user_service) { user_service_1 }
12
+ registry.user_service.users # => [:alice, :bob]
13
+
14
+ MyServiceFactory.register(:user_service) { user_service_2 }
15
+ registry.user_service.users # => [:jim, :kate]
16
+
17
+ MyServiceFactory.unregister(:user_service)
18
+ registry.user_service.users # => [:alice, :bob]
19
+
20
+ MyServiceFactory.unregister(:user_service)
21
+ registry.user_service # => NoMethodError: undefined method `user_service'
@@ -0,0 +1,11 @@
1
+ require 'rohbau/service_factory'
2
+
3
+ MyServiceFactory = Class.new(Rohbau::ServiceFactory)
4
+
5
+ MyServiceFactory.external_dependencies :user_service
6
+ MyServiceFactory.missing_dependencies # => [:user_service]
7
+ MyServiceFactory.external_dependencies_complied? # => false
8
+
9
+ MyServiceFactory.register(:user_service) { Object.new } # => :user_service
10
+ MyServiceFactory.external_dependencies_complied? # => true
11
+ MyServiceFactory.missing_dependencies # => []
@@ -0,0 +1,70 @@
1
+ module Rohbau
2
+ module Application
3
+
4
+ class RuntimeWrapper
5
+ def self.wrap(&constructor)
6
+ wrapper = Class.new do
7
+ def self.set_constructor(constructor)
8
+ @constructor = constructor
9
+ self
10
+ end
11
+
12
+ def self.new(*ignored_args)
13
+ @constructor.call
14
+ end
15
+ end
16
+
17
+ wrapper.set_constructor(constructor)
18
+ end
19
+ end
20
+
21
+ def set_application_runtime(runtime_class)
22
+ @runtime_class = runtime_class
23
+ end
24
+
25
+ def register_domain(name, namespace)
26
+ dummy = RuntimeWrapper.wrap do |cls|
27
+ namespace::Runtime.start
28
+ end
29
+
30
+ @runtime_class.register name, dummy
31
+
32
+ domains << namespace
33
+ end
34
+
35
+ def domains
36
+ @domains ||= []
37
+ end
38
+
39
+ def domain_requests
40
+ domains.map{|d| d.const_get :Request }
41
+ end
42
+
43
+ def use_case_domains
44
+ domains.select do |domain|
45
+ domain.const_defined?('UseCases')
46
+ end
47
+ end
48
+
49
+ def use_cases(use_case_domain = :all)
50
+ if use_case_domain == :all
51
+ domains = use_case_domains
52
+ else
53
+ domains = [use_case_domain]
54
+ end
55
+
56
+ domains.inject([]) do |use_cases, domain|
57
+
58
+ if domain.const_defined?('UseCases')
59
+ use_case_namespace = domain.const_get('UseCases')
60
+ use_case_namespace.constants.each do |use_case_class_name|
61
+ use_cases << use_case_namespace::const_get(use_case_class_name)
62
+ end
63
+ end
64
+
65
+ use_cases
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,78 @@
1
+ require 'rohbau/index'
2
+
3
+ module Rohbau
4
+ class DefaultMemoryGateway
5
+
6
+ def initialize(memory = Index.new, services = {})
7
+ @memory = memory
8
+ @services = services
9
+ end
10
+
11
+ def memory
12
+ @memory
13
+ end
14
+
15
+ def add(entity)
16
+ @memory.add entity
17
+ end
18
+
19
+ def bulk_add(*entities)
20
+ @memory.bulk_add(*entities)
21
+ end
22
+
23
+ def get(uid)
24
+ @memory.get(uid)
25
+ end
26
+
27
+ def update(entity)
28
+ @memory.update(entity)
29
+ end
30
+
31
+ def delete(uid)
32
+ @memory.delete(uid)
33
+ end
34
+
35
+ def bulk_delete(*uids)
36
+ @memory.bulk_delete(*uids)
37
+ end
38
+
39
+ def all
40
+ @memory.all
41
+ end
42
+
43
+ def size
44
+ @memory.size
45
+ end
46
+
47
+ protected
48
+
49
+ def service(service_name)
50
+ @services[service_name] || raise(no_service_error service_name)
51
+ end
52
+
53
+ def no_service_error(service_name)
54
+ NotImplementedError.new("#{service_name} service in #{self.class}")
55
+ end
56
+
57
+ def map(entity_name, entity)
58
+ gateway = gateway_for_entity(entity_name)
59
+
60
+ if entity.uid
61
+ result = gateway.update(entity)
62
+ else
63
+ result = gateway.add(entity)
64
+ end
65
+
66
+ result.uid
67
+ end
68
+
69
+ def unmap(entity_name, uid)
70
+ gateway_for_entity(entity_name).get(uid)
71
+ end
72
+
73
+ def gateway_for_entity(entity_name)
74
+ service(:"#{entity_name}_gateway")
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,41 @@
1
+ module Rohbau
2
+
3
+ class Entity
4
+ class << self; attr_accessor :__attributes__ end
5
+ def self.attributes(*attributes)
6
+ @__attributes__ ||= []
7
+ @__attributes__ += attributes
8
+
9
+
10
+ predicate_attributes = attributes.select do |attr|
11
+ attr =~ /\?$/
12
+ end
13
+
14
+ regular_attributes = attributes - predicate_attributes
15
+
16
+ predicate_attributes.each do |attribute|
17
+ attribute_without_predicate = attribute.to_s.gsub(/\?$/, '')
18
+ attr_accessor attribute_without_predicate
19
+
20
+ define_method attribute do ||
21
+ !!instance_variable_get(:"@#{attribute_without_predicate}")
22
+ end
23
+ end
24
+
25
+ attr_accessor(*regular_attributes)
26
+ end
27
+
28
+ def ==(other)
29
+ other && __attributes__.all? do |attr|
30
+ other.respond_to?(attr) &&
31
+ self.public_send(attr) == other.public_send(attr)
32
+ end
33
+ end
34
+
35
+ protected
36
+ def __attributes__
37
+ self.class.__attributes__ || []
38
+ end
39
+ end
40
+
41
+ end