wrapper_based 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/README.md +59 -49
- data/examples/dijkstra.rb +15 -34
- data/examples/money_transfer.rb +22 -16
- data/lib/wrapper_based/context/casting.rb +8 -4
- data/lib/wrapper_based/context/producer.rb +21 -0
- data/lib/wrapper_based/context/type_casting.rb +11 -5
- data/lib/wrapper_based/context.rb +17 -15
- data/lib/wrapper_based/dci.rb +9 -2
- data/lib/wrapper_based/roles.rb +64 -0
- data/lib/wrapper_based/version.rb +1 -1
- data/lib/wrapper_based.rb +2 -1
- data/wrapper_based.gemspec +2 -2
- metadata +7 -7
- data/examples/benchmark.rb +0 -27
- data/lib/wrapper_based/context/builder.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a512a58ee3c31a5d96debe8d835854faa1b05d1d
|
4
|
+
data.tar.gz: 0cb617aec6443efcb7972c5d015d43d4533f2918
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70e62a920819ba82bd6396b3849258e83177a8b99ba3b4d74548f71af68b4714012926e2cc904d101860da8b5dc982b2c2bd7c3bf24b9e0ae4ca3d6b6da192ce
|
7
|
+
data.tar.gz: 318f1a9ab51099e22f5e4234161ccd24931aba3067f24eedcc1ed6b593ea6b6b4e7843fe3f270379a0191322b9d622bcb37b3b8f56aa097aae623ce10c6b75e4
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[](https://badge.fury.io/rb/wrapper_based)
|
4
4
|
[](https://travis-ci.org/RichOrElse/wrapper-based)
|
5
5
|
|
6
|
-
Wrapper Based DCI
|
6
|
+
Wrapper Based DCI framework for OOP done right.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -17,17 +17,6 @@ And then execute:
|
|
17
17
|
|
18
18
|
$ bundle
|
19
19
|
|
20
|
-
Or install it yourself as:
|
21
|
-
|
22
|
-
$ gem install wrapper_based
|
23
|
-
|
24
|
-
Require DCI in your gems or save in your rails app as app/config/dci.rb:
|
25
|
-
|
26
|
-
|
27
|
-
```ruby
|
28
|
-
require 'wrapper_based/dci'
|
29
|
-
```
|
30
|
-
|
31
20
|
## Usage
|
32
21
|
|
33
22
|
[Dijkstra data](https://github.com/RichOrElse/wrapper-based/blob/master/examples/dijkstra/data.rb) |
|
@@ -35,65 +24,44 @@ require 'wrapper_based/dci'
|
|
35
24
|
Djikstra example:
|
36
25
|
|
37
26
|
```ruby
|
38
|
-
require_relative 'dijkstra/data'
|
39
|
-
|
40
|
-
module CurrentIntersection
|
41
|
-
def neighbors(manhattan:)
|
42
|
-
east_neighbor = manhattan.east_neighbor_of(self)
|
43
|
-
south_neighbor = manhattan.south_neighbor_of(self)
|
44
|
-
[south_neighbor, east_neighbor].compact # excludes nil neighbors
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
27
|
module DestinationNode
|
49
|
-
def
|
50
|
-
return [self] if equal?
|
51
|
-
|
28
|
+
def shortest_path_from(neighbor, find_shortest)
|
29
|
+
return [self] if equal? neighbor
|
30
|
+
find_shortest.path(from: neighbor)
|
52
31
|
end
|
53
32
|
end
|
54
33
|
|
55
|
-
|
34
|
+
Map = DCI::Module.new do |mod| using mod
|
56
35
|
def distance_between(a, b)
|
57
36
|
@distances[Edge.new(a, b)]
|
58
37
|
end
|
59
38
|
|
60
39
|
def distance_of(path)
|
61
|
-
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
class GetDistance < DCI::Context(:within)
|
66
|
-
within.as Map
|
67
|
-
|
68
|
-
def between(from, to)
|
69
|
-
within.distance_between(from, to)
|
40
|
+
path.each_cons(2).inject(0) { |total, (to, from)| total + distance_between(from, to) }
|
70
41
|
end
|
71
42
|
|
72
|
-
def
|
73
|
-
|
43
|
+
def neighbors(near:)
|
44
|
+
[south_neighbor_of(near), east_neighbor_of(near)].compact # excludes nil neighbors
|
74
45
|
end
|
75
46
|
end
|
76
47
|
|
77
|
-
class FindShortest < DCI::Context(:from, :
|
78
|
-
from.
|
79
|
-
to.as DestinationNode
|
80
|
-
city.as Map
|
48
|
+
class FindShortest < DCI::Context(:from, to: DestinationNode, city: Map)
|
49
|
+
def initialize(city:, from: city.root, to: city.destination) super end
|
81
50
|
|
82
51
|
def distance
|
83
52
|
city.distance_of path
|
84
53
|
end
|
85
54
|
|
86
|
-
def path
|
87
|
-
|
55
|
+
def path(from: @from)
|
56
|
+
shortest_neighbor_path(from) << from
|
88
57
|
end
|
89
58
|
|
90
59
|
private
|
91
60
|
|
92
|
-
def
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
min_by { |path| city.distance_of path }
|
61
|
+
def shortest_neighbor_path(current)
|
62
|
+
city.neighbors(near: current).
|
63
|
+
map { |neighbor| to.shortest_path_from(neighbor, self) }.
|
64
|
+
min_by { |neighbor_path| city.distance_of neighbor_path }
|
97
65
|
end
|
98
66
|
end
|
99
67
|
```
|
@@ -102,7 +70,7 @@ end
|
|
102
70
|
|
103
71
|
## Context methods
|
104
72
|
|
105
|
-
### to_proc
|
73
|
+
### context#to_proc
|
106
74
|
|
107
75
|
Returns call method as a Proc.
|
108
76
|
|
@@ -118,6 +86,48 @@ Square brackets are alias for call method.
|
|
118
86
|
TransferMoney[from: source_account, to: destination_account][amount: 100]
|
119
87
|
```
|
120
88
|
|
89
|
+
### context#rebind(**params)
|
90
|
+
Assigns object to role.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
add_member = Evaluate.new(to: 'Justice League')
|
94
|
+
['Batman', Superman', 'Wonder Woman'].each do |founder|
|
95
|
+
add_member.rebind(member: founder).(recruit: 'Supergirl')
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
## Context class methods
|
100
|
+
|
101
|
+
### klass#call(**params)
|
102
|
+
|
103
|
+
A shortcut for instantiating the context by passing the collaborators and then executing the context call method.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
Funds::TransferMoney.(from: @account1, to: @account2, amount: 50)
|
107
|
+
```
|
108
|
+
|
109
|
+
Which is equivalent to:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
Funds::TransferMoney.new(from: @account1, to: @account2, amount: 50).call
|
113
|
+
```
|
114
|
+
|
115
|
+
## DCI::Module
|
116
|
+
|
117
|
+
Extention module for supporting procedural code. Define a block with the 'new' method and pass the 'mod' parameter to 'using' keyword.
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
AwesomeSinging = TypeWrapper::Module.new do |mod| using mod
|
121
|
+
def sing
|
122
|
+
"#{name} sings #{song}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def song
|
126
|
+
"Everything is AWESOME!!!"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
121
131
|
## Development
|
122
132
|
|
123
133
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/examples/dijkstra.rb
CHANGED
@@ -1,62 +1,43 @@
|
|
1
1
|
require_relative 'dijkstra/data'
|
2
2
|
# See https://github.com/RichOrElse/wrapper-based/blob/master/test/dijkstra_test.rb
|
3
3
|
|
4
|
-
module CurrentIntersection
|
5
|
-
def neighbors(manhattan:)
|
6
|
-
east_neighbor = manhattan.east_neighbor_of(self)
|
7
|
-
south_neighbor = manhattan.south_neighbor_of(self)
|
8
|
-
[south_neighbor, east_neighbor].compact # excludes nil neighbors
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
4
|
module DestinationNode
|
13
|
-
def
|
14
|
-
return [self] if equal?
|
15
|
-
|
5
|
+
def shortest_path_from(neighbor, find_shortest)
|
6
|
+
return [self] if equal? neighbor
|
7
|
+
find_shortest.path(from: neighbor)
|
16
8
|
end
|
17
9
|
end
|
18
10
|
|
19
|
-
|
11
|
+
Map = DCI::Module.new do |mod| using mod
|
20
12
|
def distance_between(a, b)
|
21
13
|
@distances[Edge.new(a, b)]
|
22
14
|
end
|
23
15
|
|
24
16
|
def distance_of(path)
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class GetDistance < DCI::Context(:within)
|
30
|
-
within.as Map
|
31
|
-
|
32
|
-
def between(from, to)
|
33
|
-
within.distance_between(from, to)
|
17
|
+
path.each_cons(2).inject(0) { |total, (to, from)| total + distance_between(from, to) }
|
34
18
|
end
|
35
19
|
|
36
|
-
def
|
37
|
-
|
20
|
+
def neighbors(near:)
|
21
|
+
[south_neighbor_of(near), east_neighbor_of(near)].compact # excludes nil neighbors
|
38
22
|
end
|
39
23
|
end
|
40
24
|
|
41
|
-
class FindShortest < DCI::Context(:from, :
|
42
|
-
from.
|
43
|
-
to.as DestinationNode
|
44
|
-
city.as Map
|
25
|
+
class FindShortest < DCI::Context(:from, to: DestinationNode, city: Map)
|
26
|
+
def initialize(city:, from: city.root, to: city.destination) super end
|
45
27
|
|
46
28
|
def distance
|
47
29
|
city.distance_of path
|
48
30
|
end
|
49
31
|
|
50
|
-
def path
|
51
|
-
|
32
|
+
def path(from: @from)
|
33
|
+
shortest_neighbor_path(from) << from
|
52
34
|
end
|
53
35
|
|
54
36
|
private
|
55
37
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
min_by { |path| city.distance_of path }
|
38
|
+
def shortest_neighbor_path(current)
|
39
|
+
city.neighbors(near: current).
|
40
|
+
map { |neighbor| to.shortest_path_from(neighbor, self) }.
|
41
|
+
min_by { |neighbor_path| city.distance_of neighbor_path }
|
61
42
|
end
|
62
43
|
end
|
data/examples/money_transfer.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
LogTransaction = Struct.new(:transaction_type, :amount, :account_number)
|
2
|
-
|
3
1
|
module Funds
|
4
2
|
Insufficient = Class.new(StandardError)
|
5
3
|
|
@@ -16,33 +14,41 @@ module Funds
|
|
16
14
|
end
|
17
15
|
end
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
module Logging
|
18
|
+
def log(transfer_type, amount, account, at: Time.now)
|
19
|
+
self << [transfer_type, account.number, amount, at]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class TransferMoney < DCI::Context(:amount, from: SourceAccount, to: DestinationAccount, events: Logging)
|
24
|
+
def initialize(amount: 0, events: [], **accounts)
|
25
|
+
super
|
26
|
+
end
|
22
27
|
|
23
28
|
def withdraw(amount)
|
24
29
|
from.decrease_balance_by(amount)
|
25
|
-
|
30
|
+
events.log "Withdrew", amount, from
|
26
31
|
end
|
27
32
|
|
28
33
|
def deposit(amount)
|
29
34
|
to.increase_balance_by(amount)
|
30
|
-
|
35
|
+
events.log "Deposited", amount, to
|
31
36
|
end
|
32
37
|
|
33
|
-
def
|
34
|
-
|
38
|
+
def transfer(amount)
|
39
|
+
withdraw(amount)
|
40
|
+
deposit(amount)
|
35
41
|
end
|
36
42
|
|
37
|
-
def call(amount:)
|
38
|
-
|
39
|
-
|
43
|
+
def call(amount: @amount)
|
44
|
+
transfer(amount)
|
45
|
+
return :success, { log: @events }, accounts
|
40
46
|
rescue Funds::Insufficient => error
|
41
|
-
|
47
|
+
return :failure, { message: error.message }, accounts
|
42
48
|
end
|
43
|
-
end
|
44
49
|
|
45
|
-
|
46
|
-
|
50
|
+
def accounts
|
51
|
+
[@from, @to]
|
52
|
+
end
|
47
53
|
end
|
48
54
|
end
|
@@ -2,12 +2,12 @@ require 'set'
|
|
2
2
|
|
3
3
|
module WrapperBased
|
4
4
|
class Context::Casting
|
5
|
-
attr_reader :name
|
5
|
+
attr_reader :name
|
6
6
|
|
7
|
-
def initialize(name,
|
7
|
+
def initialize(name, wrappers)
|
8
8
|
@name = name.to_sym
|
9
9
|
@casting = Set.new
|
10
|
-
@
|
10
|
+
@wrappers = wrappers
|
11
11
|
end
|
12
12
|
|
13
13
|
def as(extention)
|
@@ -15,8 +15,12 @@ module WrapperBased
|
|
15
15
|
self
|
16
16
|
end
|
17
17
|
|
18
|
+
def wrapper_for(*args)
|
19
|
+
@wrappers[args]
|
20
|
+
end
|
21
|
+
|
18
22
|
def cast_type(type)
|
19
|
-
|
23
|
+
wrapper_for type, *@casting
|
20
24
|
end
|
21
25
|
|
22
26
|
def typecast(actor)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module WrapperBased
|
2
|
+
class Context
|
3
|
+
class Producer
|
4
|
+
def initialize(wrapper_for)
|
5
|
+
@wrapper_cache = Hash.new do |cache, type_casting|
|
6
|
+
cache[type_casting] = wrapper_for[*type_casting]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def produce(*supporting, **leading, &script)
|
11
|
+
wrappers = @wrapper_cache
|
12
|
+
roles = supporting.map(&:to_sym) | leading.keys
|
13
|
+
Class.new(Context) do
|
14
|
+
roles.each { |role| add_role role, Casting.new(role, wrappers) }
|
15
|
+
leading.each_pair { |role, trait| send(role).as trait }
|
16
|
+
class_eval(&script) unless script.nil?
|
17
|
+
end
|
18
|
+
end # produce method
|
19
|
+
end # Producer class
|
20
|
+
end # Context class
|
21
|
+
end # WrapperBased module
|
@@ -2,6 +2,12 @@ require 'delegate'
|
|
2
2
|
|
3
3
|
module WrapperBased
|
4
4
|
module Context::TypeCasting
|
5
|
+
refine Object do
|
6
|
+
def as_role_played_by(actor)
|
7
|
+
actor
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
refine NilClass do
|
6
12
|
def as_role_played_by(actor)
|
7
13
|
yield
|
@@ -10,7 +16,7 @@ module WrapperBased
|
|
10
16
|
|
11
17
|
refine Delegator do
|
12
18
|
def as_role_played_by(actor)
|
13
|
-
return replace_role_player_with(actor) if
|
19
|
+
return replace_role_player_with(actor) if actor.instance_of?(role_type)
|
14
20
|
yield
|
15
21
|
end
|
16
22
|
|
@@ -19,9 +25,9 @@ module WrapperBased
|
|
19
25
|
self
|
20
26
|
end
|
21
27
|
|
22
|
-
def
|
23
|
-
|
28
|
+
def role_type
|
29
|
+
__getobj__.class
|
24
30
|
end
|
25
|
-
end
|
26
|
-
end
|
31
|
+
end # Delegator refinement
|
32
|
+
end # TypeCasting module
|
27
33
|
end
|
@@ -1,8 +1,13 @@
|
|
1
1
|
module WrapperBased
|
2
2
|
class Context
|
3
3
|
def initialize(**where)
|
4
|
-
@
|
5
|
-
where
|
4
|
+
@_casting_director_ = CastingDirector.new(self.class)
|
5
|
+
rebind where
|
6
|
+
end
|
7
|
+
|
8
|
+
def rebind(**where)
|
9
|
+
where.each { |role, player| public_send :"#{role}=", player }
|
10
|
+
self
|
6
11
|
end
|
7
12
|
|
8
13
|
def to_proc
|
@@ -18,41 +23,38 @@ module WrapperBased
|
|
18
23
|
class << self
|
19
24
|
alias_method :[], :new
|
20
25
|
|
26
|
+
def call(**where)
|
27
|
+
new(where).call
|
28
|
+
end
|
29
|
+
|
21
30
|
def cast_as(role, actor)
|
22
31
|
send(role).typecast(actor)
|
23
32
|
end
|
24
33
|
|
25
34
|
protected
|
26
35
|
|
27
|
-
def add_role(role,
|
36
|
+
def add_role(role, casting)
|
28
37
|
add_reader_for(role)
|
29
38
|
add_writer_for(role)
|
30
|
-
|
39
|
+
add_role_to_class role, casting
|
31
40
|
end
|
32
41
|
|
33
42
|
def add_reader_for(role)
|
34
43
|
define_method(role) do
|
35
|
-
@
|
44
|
+
@_casting_director_.fetch(role) { raise UnassignedRole, "Role '#{role}' is missing.", caller }
|
36
45
|
end
|
37
46
|
end
|
38
47
|
|
39
48
|
def add_writer_for(role)
|
40
49
|
role_player = :"@#{role}"
|
41
|
-
|
42
50
|
define_method(:"#{role}=") do |actor|
|
43
51
|
instance_variable_set(role_player, actor)
|
44
|
-
@
|
52
|
+
@_casting_director_.cast_as role, actor
|
45
53
|
end
|
46
54
|
end
|
47
55
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
singleton_class.class_eval do
|
52
|
-
define_method(role) { class_variable_get role_casting }
|
53
|
-
end
|
54
|
-
|
55
|
-
class_variable_set role_casting, casting
|
56
|
+
def add_role_to_class(role, casting)
|
57
|
+
define_singleton_method(role) { casting }
|
56
58
|
end
|
57
59
|
end # class methods
|
58
60
|
end # Context class
|
data/lib/wrapper_based/dci.rb
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
require "wrapper_based"
|
2
1
|
require "type_wrapper"
|
3
2
|
|
4
|
-
DCI
|
3
|
+
module DCI
|
4
|
+
Module = Class.new(TypeWrapper::Module)
|
5
|
+
|
6
|
+
@@context_producer = WrapperBased::Context::Producer.new(TypeWrapper)
|
7
|
+
|
8
|
+
def self.Context(*args, &block)
|
9
|
+
@@context_producer.produce(*args, &block)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module WrapperBased
|
2
|
+
class Roles < Module
|
3
|
+
Unassigned = Class.new(StandardError)
|
4
|
+
|
5
|
+
def initialize(wrappers, *roles, **where, &block)
|
6
|
+
@casting_agent = (where.keys | roles.map(&:to_sym)).inject {|cast, role| cast[role] = Casting.new(role, wrappers) }
|
7
|
+
@casting_agent.keys.each { |role| add_role role }
|
8
|
+
where.each_pair {|role, trait| @casting[role].as trait }
|
9
|
+
define_casting_director(@casting_agent)
|
10
|
+
include InstanceMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
def cast_as role, actor
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def defing_casting_director(casting_agent)
|
18
|
+
define_method(:_casting_director_) { @_casting_director ||= CastingDirector.new(casting_agent) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def cast_as(role, actor)
|
22
|
+
@casting[role].typecast actor
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_role(role)
|
26
|
+
add_reader_for(role)
|
27
|
+
add_writer_for(role)
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_reader_for(role)
|
31
|
+
define_method(role) do
|
32
|
+
_casting_director_.fetch(role) { raise Roles::Unassigned, "Role '#{role}' is missing.", caller }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_writer_for(role)
|
37
|
+
role_player = :"@#{role}"
|
38
|
+
define_method(:"#{role}=") do |actor|
|
39
|
+
instance_variable_set(role_player, actor)
|
40
|
+
_casting_director_.cast_as role, actor
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_role_to_class(role, casting)
|
45
|
+
define_singleton_method(role) { casting }
|
46
|
+
end
|
47
|
+
|
48
|
+
def define_casting_director
|
49
|
+
roles = self
|
50
|
+
end
|
51
|
+
|
52
|
+
def included(base)
|
53
|
+
base.extend ClassMethods
|
54
|
+
end
|
55
|
+
|
56
|
+
module InstanceMethods
|
57
|
+
def rebind(**where, &block)
|
58
|
+
where.each { |role, player| public_send :"#{role}=", player }
|
59
|
+
instance_eval &block if block_given?
|
60
|
+
self
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/wrapper_based.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require "wrapper_based/version"
|
2
2
|
require "wrapper_based/context"
|
3
|
-
require "wrapper_based/context/
|
3
|
+
require "wrapper_based/context/producer"
|
4
4
|
require "wrapper_based/context/casting"
|
5
5
|
require "wrapper_based/context/type_casting"
|
6
6
|
require "wrapper_based/context/casting_director"
|
7
|
+
require "wrapper_based/dci"
|
7
8
|
|
8
9
|
module WrapperBased
|
9
10
|
end
|
data/wrapper_based.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Ritchie Paul Buitre"]
|
10
10
|
spec.email = ["ritchie@richorelse.com"]
|
11
11
|
|
12
|
-
spec.summary = "Wrapper Based DCI
|
12
|
+
spec.summary = "Wrapper Based DCI framework for OOP done right."
|
13
13
|
spec.homepage = "https://github.com/RichOrElse/wrapper-based/"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
spec.required_ruby_version = ">= 2.1.0"
|
23
23
|
|
24
|
-
spec.add_runtime_dependency "type_wrapper", "~> 1.
|
24
|
+
spec.add_runtime_dependency "type_wrapper", "~> 1.2"
|
25
25
|
|
26
26
|
spec.add_development_dependency "bundler", "~> 1.15"
|
27
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wrapper_based
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ritchie Paul Buitre
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-07-
|
11
|
+
date: 2017-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: type_wrapper
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,18 +81,18 @@ files:
|
|
81
81
|
- Rakefile
|
82
82
|
- bin/console
|
83
83
|
- bin/setup
|
84
|
-
- examples/benchmark.rb
|
85
84
|
- examples/dijkstra.rb
|
86
85
|
- examples/dijkstra/data.rb
|
87
86
|
- examples/money_transfer.rb
|
88
87
|
- examples/toy_shop.rb
|
89
88
|
- lib/wrapper_based.rb
|
90
89
|
- lib/wrapper_based/context.rb
|
91
|
-
- lib/wrapper_based/context/builder.rb
|
92
90
|
- lib/wrapper_based/context/casting.rb
|
93
91
|
- lib/wrapper_based/context/casting_director.rb
|
92
|
+
- lib/wrapper_based/context/producer.rb
|
94
93
|
- lib/wrapper_based/context/type_casting.rb
|
95
94
|
- lib/wrapper_based/dci.rb
|
95
|
+
- lib/wrapper_based/roles.rb
|
96
96
|
- lib/wrapper_based/version.rb
|
97
97
|
- wrapper_based.gemspec
|
98
98
|
homepage: https://github.com/RichOrElse/wrapper-based/
|
@@ -118,5 +118,5 @@ rubyforge_project:
|
|
118
118
|
rubygems_version: 2.6.8
|
119
119
|
signing_key:
|
120
120
|
specification_version: 4
|
121
|
-
summary: Wrapper Based DCI
|
121
|
+
summary: Wrapper Based DCI framework for OOP done right.
|
122
122
|
test_files: []
|
data/examples/benchmark.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# Derived from https://tonyarcieri.com/dci-in-ruby-is-completely-broken
|
2
|
-
require 'rubygems'
|
3
|
-
require 'benchmark/ips'
|
4
|
-
require 'wrapper_based'
|
5
|
-
|
6
|
-
class ExampleClass
|
7
|
-
def foo; 42; end
|
8
|
-
end
|
9
|
-
|
10
|
-
module ExampleMixin
|
11
|
-
def foo; 43; end
|
12
|
-
end
|
13
|
-
|
14
|
-
wrapper = WrapperBased::FORWARDING[ExampleClass, ExampleMixin]
|
15
|
-
|
16
|
-
Benchmark.ips do |bm|
|
17
|
-
bm.report("without dci") { ExampleClass.new.foo }
|
18
|
-
bm.report("with wrapper") do
|
19
|
-
wrapper.new(ExampleClass.new).foo
|
20
|
-
end
|
21
|
-
bm.report("with extend") do
|
22
|
-
obj = ExampleClass.new
|
23
|
-
obj.extend(ExampleMixin)
|
24
|
-
obj.foo
|
25
|
-
end
|
26
|
-
bm.compare!
|
27
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module WrapperBased
|
2
|
-
class Context::Builder < Module
|
3
|
-
def initialize(wrapper_for)
|
4
|
-
class_variable_set :@@wrapper_for,
|
5
|
-
Hash.new { |cache, type_casting| cache[type_casting] = wrapper_for[*type_casting] }
|
6
|
-
end
|
7
|
-
|
8
|
-
def wrapper_for(*type_casting)
|
9
|
-
class_variable_get(:@@wrapper_for)[type_casting]
|
10
|
-
end
|
11
|
-
|
12
|
-
def Context(*roles, &block)
|
13
|
-
dci = self
|
14
|
-
Class.new(WrapperBased::Context) do
|
15
|
-
roles.each { |role| add_role role, dci }
|
16
|
-
class_eval(&block) unless block.nil?
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end # Context::Builder class
|
20
|
-
end # WrapperBased module
|