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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8250109a727470549a4a5ad7eeeb2b83deb22ded
4
- data.tar.gz: aad939be5697e39f97d8adfcb2978ef723702516
3
+ metadata.gz: a512a58ee3c31a5d96debe8d835854faa1b05d1d
4
+ data.tar.gz: 0cb617aec6443efcb7972c5d015d43d4533f2918
5
5
  SHA512:
6
- metadata.gz: 71ec411aaa5a9ebaeab67749f5adcc66e1b2921cbb58e22ce3a49385e4d8173a8502f3582c6187af6a3829cfda489ff81eb734ce5d55e6b559409d287a80d72e
7
- data.tar.gz: 183610fab65d79dee5b6c08f8f1bc849718fb1241478d9937bff0fe283d3ebd429fdbb1d493122bd2c52109703d6c1dd6152cb301a33b2f602be07b748beb8eb
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 implementation in Ruby.
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 shortest_path(from:, within:)
50
- return [self] if equal? from
51
- FindShortest[to: self, from: from, city: within].path
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
- module Map
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
- GetDistance[within: self].of(path)
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 of(path)
73
- path.reverse.each_cons(2).inject(0) { |total_distance, pair| total_distance + between(*pair) }
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, :to, :city)
78
- from.as CurrentIntersection
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
- shortest_path_from_city_neighbors << @from
55
+ def path(from: @from)
56
+ shortest_neighbor_path(from) << from
88
57
  end
89
58
 
90
59
  private
91
60
 
92
- def shortest_path_from_city_neighbors
93
- from.
94
- neighbors(manhattan: @city).
95
- map { |neighbor| to.shortest_path from: neighbor, within: @city }.
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 shortest_path(from:, within:)
14
- return [self] if equal? from
15
- FindShortest[to: self, from: from, city: within].path
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
- module Map
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
- GetDistance[within: self].of(path)
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 of(path)
37
- path.reverse.each_cons(2).inject(0) { |total_distance, pair| total_distance + between(*pair) }
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, :to, :city)
42
- from.as CurrentIntersection
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
- shortest_path_from_city_neighbors << @from
32
+ def path(from: @from)
33
+ shortest_neighbor_path(from) << from
52
34
  end
53
35
 
54
36
  private
55
37
 
56
- def shortest_path_from_city_neighbors
57
- from.
58
- neighbors(manhattan: @city).
59
- map { |neighbor| to.shortest_path from: neighbor, within: @city }.
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
@@ -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
- class TransferMoney < DCI::Context(:from, :to)
20
- from.as SourceAccount
21
- to.as DestinationAccount
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
- LogTransaction["Withdraw", amount, from.number]
30
+ events.log "Withdrew", amount, from
26
31
  end
27
32
 
28
33
  def deposit(amount)
29
34
  to.increase_balance_by(amount)
30
- LogTransaction["Deposit", amount, to.number]
35
+ events.log "Deposited", amount, to
31
36
  end
32
37
 
33
- def accounts
34
- [@from, @to]
38
+ def transfer(amount)
39
+ withdraw(amount)
40
+ deposit(amount)
35
41
  end
36
42
 
37
- def call(amount:)
38
- transaction_logs = [withdraw(amount), deposit(amount)]
39
- [:success, { logs: transaction_logs }, accounts]
43
+ def call(amount: @amount)
44
+ transfer(amount)
45
+ return :success, { log: @events }, accounts
40
46
  rescue Funds::Insufficient => error
41
- [:failure, { message: error.message }, accounts]
47
+ return :failure, { message: error.message }, accounts
42
48
  end
43
- end
44
49
 
45
- def self.transfer(**where)
46
- TransferMoney[**where]
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, :dci
5
+ attr_reader :name
6
6
 
7
- def initialize(name, dci)
7
+ def initialize(name, wrappers)
8
8
  @name = name.to_sym
9
9
  @casting = Set.new
10
- @dci = dci
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
- @dci.wrapper_for type, *@casting
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 role_type_same_as?(actor)
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 role_type_same_as?(actor)
23
- actor.instance_of?(__getobj__.class)
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
- @casting_director = CastingDirector.new(self.class)
5
- where.each { |role, player| send :"#{role}=", player }
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, dci)
36
+ def add_role(role, casting)
28
37
  add_reader_for(role)
29
38
  add_writer_for(role)
30
- add_to_class_cast_for role, Casting.new(role, dci)
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
- @casting_director.fetch(role) { raise UnassignedRole, "Role '#{role}' is missing.", caller }
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
- @casting_director.cast_as role, actor
52
+ @_casting_director_.cast_as role, actor
45
53
  end
46
54
  end
47
55
 
48
- def add_to_class_cast_for(role, casting)
49
- role_casting = :"@@#{role}"
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
@@ -1,4 +1,11 @@
1
- require "wrapper_based"
2
1
  require "type_wrapper"
3
2
 
4
- DCI = WrapperBased::Context::Builder.new(TypeWrapper)
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
@@ -1,3 +1,3 @@
1
1
  module WrapperBased
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  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/builder"
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
@@ -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 implementation in Ruby."
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.0"
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.0.0
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-10 00:00:00.000000000 Z
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.0'
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.0'
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 implementation in Ruby.
121
+ summary: Wrapper Based DCI framework for OOP done right.
122
122
  test_files: []
@@ -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