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 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