wrapper_based 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/wrapper_based.svg)](https://badge.fury.io/rb/wrapper_based)
|
4
4
|
[![Build Status](https://travis-ci.org/RichOrElse/wrapper-based.svg?branch=master)](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
|