dci 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.ruby CHANGED
@@ -26,18 +26,18 @@ repositories:
26
26
  scm: git
27
27
  name: upstream
28
28
  resources:
29
- home: https://rubyworks.github.com/dci
30
- code: https://github.com/rubyworks/dci
29
+ home: http://rubyworks.github.com/dci
30
+ code: http://github.com/rubyworks/dci
31
31
  mail: http://groups.google.com/groups/rubyworks-mailinglist
32
32
  extra: {}
33
33
  load_path:
34
34
  - lib
35
35
  revision: 0
36
- version: 0.1.0
36
+ version: 0.2.0
37
37
  name: dci
38
38
  title: DCI
39
39
  summary: DCI for Ruby
40
40
  created: '2011-03-04'
41
41
  description: Faithful DCI framework for Ruby application development.
42
42
  organization: Rubyworks
43
- date: '2012-02-07'
43
+ date: '2012-02-08'
@@ -28,14 +28,14 @@ a balance of $100. (We're generous like that.)
28
28
  We set up two Roles, one role for withdrawing money from an account,
29
29
  and one for depositing money into an account.
30
30
 
31
- class Account::TransferWithdraw < Role
31
+ class Account::TransferWithdraw < DCI::Role
32
32
  def transfer(amount)
33
33
  decrease_balance(amount)
34
34
  #log "Tranfered $#{amount} from account ##{account_id}."
35
35
  end
36
36
  end
37
37
 
38
- class Account::TransferDeposit < Role
38
+ class Account::TransferDeposit < DCI::Role
39
39
  def transfer(amount)
40
40
  increase_balance(amount)
41
41
  #log "Tranfered $#{amount} into account ##{account_id}."
@@ -46,7 +46,7 @@ Now we create a Context which will assign accounts to the roles
46
46
  and used to perfomr the transfer.
47
47
 
48
48
  # We can think of a context as setting a scene.
49
- class Account::Transfer < Context
49
+ class Account::Transfer < DCI::Context
50
50
  role :source_account => Account::TransferWithdraw
51
51
  role :destination_account => Account::TransferDeposit
52
52
 
@@ -1,89 +1,105 @@
1
- # Context - The Context is the class (or its instance) whose code includes the roles
2
- # for a given algorithm, scenario, or use case, as well as the code to map these
3
- # roles into objects at run time and to enact the use case. Each role is bound
4
- # to exactly one object during any given use case enactment; however, a single
5
- # object may simultaneously play several roles. A context is instantiated at the
6
- # beginning of the enactment of an algorithm, scenario, or use case. In summary,
7
- # a Context comprises use cases and algorithms in which data objects are used
8
- # through specific Roles.
9
- #
10
- # Each context represents one or more use cases. A context object is instantiated
11
- # for each enactment of a use case for which it is responsible. Its main job
12
- # is to identify the objects that will participate in the use case and to
13
- # assign them to play the Roles which carry out the use case through their
14
- # responsibilities. A role may comprise methods, and each method is some small
15
- # part of the logic of an algorithm implementing a use case. Role methods run
16
- # in the context of an object that is selected by the context to play that role
17
- # for the current use case enactment. The role-to-object bindings that take place
18
- # in a context can be contrasted with the polymorphism of vernacular object-oriented
19
- # programming. The overall business functionality is the sum of complex, dynamic
20
- # networks of methods decentralized in multiple contexts and their roles.
21
- #
22
- # Each context is a scope that includes identifiers that correspond to its roles.
23
- # Any role executing within that context can refer to the other roles in that
24
- # context through these identifiers. These identifiers have come to be called
25
- # methodless roles. At use case enactment time, each and every one of these
26
- # identifiers becomes bound to an object playing the corresponding Role for
27
- # this Context.
28
- #
29
- # An example of a context could be a wire transfer between two accounts,
30
- # where data models (the banking accounts) are used through roles named
31
- # SourceAccount and # DestinationAccount.
32
- #
33
- # class Account::Transfer < Context
34
- # role :source_account => Account::TransferWithdraw
35
- # role :destination_account => Account::TransferDeposit
36
- #
37
- # def initialize(source_account, destination_account)
38
- # self.source_account = source_account
39
- # self.destination_account = destination_account
40
- # end
41
- #
42
- # def transfer(amount)
43
- # roles.each{ |role| role.transfer(amount) }
44
- # end
45
- # end
46
- #
47
- class Context
1
+ module DCI
48
2
 
49
- # Define a role given the name the role will use in this context,
50
- # and the role class that is to be played.
3
+ # Context - The Context is the class (or its instance) whose code includes the roles
4
+ # for a given algorithm, scenario, or use case, as well as the code to map these
5
+ # roles into objects at run time and to enact the use case. Each role is bound
6
+ # to exactly one object during any given use case enactment; however, a single
7
+ # object may simultaneously play several roles. A context is instantiated at the
8
+ # beginning of the enactment of an algorithm, scenario, or use case. In summary,
9
+ # a Context comprises use cases and algorithms in which data objects are used
10
+ # through specific Roles.
51
11
  #
52
- def self.role(name_to_role)
53
- name_to_role.each do |name, role|
54
- define_method("role_#{name}"){ role }
12
+ # Each context represents one or more use cases. A context object is instantiated
13
+ # for each enactment of a use case for which it is responsible. Its main job
14
+ # is to identify the objects that will participate in the use case and to
15
+ # assign them to play the Roles which carry out the use case through their
16
+ # responsibilities. A role may comprise methods, and each method is some small
17
+ # part of the logic of an algorithm implementing a use case. Role methods run
18
+ # in the context of an object that is selected by the context to play that role
19
+ # for the current use case enactment. The role-to-object bindings that take place
20
+ # in a context can be contrasted with the polymorphism of vernacular object-oriented
21
+ # programming. The overall business functionality is the sum of complex, dynamic
22
+ # networks of methods decentralized in multiple contexts and their roles.
23
+ #
24
+ # Each context is a scope that includes identifiers that correspond to its roles.
25
+ # Any role executing within that context can refer to the other roles in that
26
+ # context through these identifiers. These identifiers have come to be called
27
+ # methodless roles. At use case enactment time, each and every one of these
28
+ # identifiers becomes bound to an object playing the corresponding Role for
29
+ # this Context.
30
+ #
31
+ # An example of a context could be a wire transfer between two accounts,
32
+ # where data models (the banking accounts) are used through roles named
33
+ # SourceAccount and # DestinationAccount.
34
+ #
35
+ # class Account::Transfer < Context
36
+ # role :source_account => Account::TransferWithdraw
37
+ # role :destination_account => Account::TransferDeposit
38
+ #
39
+ # def initialize(source_account, destination_account)
40
+ # self.source_account = source_account
41
+ # self.destination_account = destination_account
42
+ # end
43
+ #
44
+ # def transfer(amount)
45
+ # roles.each{ |role| role.transfer(amount) }
46
+ # end
47
+ # end
48
+ #
49
+ class Context
55
50
 
56
- module_eval %{
57
- def #{name}=(data)
58
- @#{name} = role_#{name}.new(data)
59
- end
51
+ # Define a role given the name the role will use in this context,
52
+ # and the role class that is to be played.
53
+ #
54
+ def self.role(name_to_role)
55
+ @roles = nil # reset
56
+
57
+ name_to_role.each do |name, role|
58
+ define_method("role_#{name}"){ role }
60
59
 
61
- def #{name}
62
- @#{name}
60
+ module_eval %{
61
+ def #{name}=(data)
62
+ @#{name} = role_#{name}.new(data)
63
+ end
64
+
65
+ def #{name}
66
+ @#{name}
67
+ end
68
+ }
69
+ end
70
+ end
71
+
72
+ # Return a list of the names of defined roles.
73
+ #
74
+ # TODO: Consider private vs public roles.
75
+ def self.roles
76
+ @roles ||= (
77
+ list = []
78
+ instance_methods.each do |name|
79
+ next unless name.to_s.start_with?('role_')
80
+ list << name.to_s[5..-1].to_sym
63
81
  end
64
- }
82
+ list
83
+ )
65
84
  end
66
- end
67
85
 
68
- # The default contructor can be used to assign roles via
69
- # a settings hash.
70
- #
71
- def initialize(settings={})
72
- settings.each do |k,v|
73
- __send__("#{k}=", v)
86
+ # The default contructor can be used to assign roles via
87
+ # a settings hash.
88
+ #
89
+ def initialize(settings={})
90
+ settings.each do |k,v|
91
+ __send__("#{k}=", v)
92
+ end
74
93
  end
75
- end
76
94
 
77
- # Returns a list of all roles in the context.
78
- #
79
- # @todo Return value should probably be cached.
80
- def roles
81
- list = []
82
- methods.each do |name|
83
- next unless name.to_s.start_with?('role_')
84
- list << __send__(name.to_s.sub('role_',''))
95
+ # Return Array of all role instances in the context.
96
+ #
97
+ def roles
98
+ self.class.roles.map do |name|
99
+ __send__(name)
100
+ end
85
101
  end
86
- list
102
+
87
103
  end
88
104
 
89
105
  end
@@ -1,53 +1,56 @@
1
- # Interaction - The Interaction is "what the system does." The Interaction
2
- # is implemented as Roles which are played by objects at run time. These objects
3
- # combine the state and methods of a Data (domain) object with methods (but no
4
- # state, as Roles are stateless) from one or more Roles. In good DCI style,
5
- # a Role addresses another object only in terms of its (methodless) Role. There
6
- # is a special Role called `@self` which binds to the object playing the current
7
- # Role. Code within a Role method may invoke a method on `@self` and thereby
8
- # invoke a method of the Data part of the current object. One curious aspect
9
- # of DCI is that these bindings are guaranteed to be in place only at run time
10
- # (using a variety of approaches and conventions; C++ templates can be used to
11
- # guarantee that the bindings will succeed). This means that Interactions—the
12
- # Role methods—are generic. In fact, some DCI implementations use generics or
13
- # templates for Roles.
14
- #
15
- # A Role is a stateless programming construct that corresponds to the end user's
16
- # mental model of some entity in the system. A Role represents a collection of
17
- # responsibilities. Whereas vernacular object-oriented programming speaks of
18
- # objects or classes as the loci of responsibilities, DCI ascribes them to Roles.
19
- # An object participating in a use case has responsibilities: those that it takes
20
- # on as a result of playing a particular Role.
21
- #
22
- # In the money transfer use case, for example, the role methods in the
23
- # SourceAccount and DestinationAccount enact the actual transfer.
24
- #
25
- # class Account::TransferWithdraw < Role
26
- # def transfer(amount)
27
- # decrease_balance(amount)
28
- # log "Tranfered from account #{account_id} $#{amount}"
29
- # end
30
- # end
31
- #
32
- # class Account::TransferDepoit < Role
33
- # def transfer(amount)
34
- # increase_balance(amount)
35
- # log "Tranfered into account #{account_id} $#{amount}"
36
- # end
37
- # end
38
- #
39
- class Role
1
+ module DCI
40
2
 
3
+ # Interaction - The Interaction is "what the system does." The Interaction
4
+ # is implemented as Roles which are played by objects at run time. These objects
5
+ # combine the state and methods of a Data (domain) object with methods (but no
6
+ # state, as Roles are stateless) from one or more Roles. In good DCI style,
7
+ # a Role addresses another object only in terms of its (methodless) Role. There
8
+ # is a special Role called `@self` which binds to the object playing the current
9
+ # Role. Code within a Role method may invoke a method on `@self` and thereby
10
+ # invoke a method of the Data part of the current object. One curious aspect
11
+ # of DCI is that these bindings are guaranteed to be in place only at run time
12
+ # (using a variety of approaches and conventions; C++ templates can be used to
13
+ # guarantee that the bindings will succeed). This means that Interactions—the
14
+ # Role methods—are generic. In fact, some DCI implementations use generics or
15
+ # templates for Roles.
41
16
  #
42
- def initialize(player)
43
- @self = player
44
- end
45
-
17
+ # A Role is a stateless programming construct that corresponds to the end user's
18
+ # mental model of some entity in the system. A Role represents a collection of
19
+ # responsibilities. Whereas vernacular object-oriented programming speaks of
20
+ # objects or classes as the loci of responsibilities, DCI ascribes them to Roles.
21
+ # An object participating in a use case has responsibilities: those that it takes
22
+ # on as a result of playing a particular Role.
23
+ #
24
+ # In the money transfer use case, for example, the role methods in the
25
+ # SourceAccount and DestinationAccount enact the actual transfer.
26
+ #
27
+ # class Account::TransferWithdraw < Role
28
+ # def transfer(amount)
29
+ # decrease_balance(amount)
30
+ # log "Tranfered from account #{account_id} $#{amount}"
31
+ # end
32
+ # end
33
+ #
34
+ # class Account::TransferDepoit < Role
35
+ # def transfer(amount)
36
+ # increase_balance(amount)
37
+ # log "Tranfered into account #{account_id} $#{amount}"
38
+ # end
39
+ # end
46
40
  #
47
- # @todo Should use #public_send?
48
- def method_missing(s, *a, &b)
49
- @self.__send__(s, *a, &b)
41
+ class Role
42
+
43
+ #
44
+ def initialize(player)
45
+ @self = player
46
+ end
47
+
48
+ #
49
+ # @todo Should use #public_send?
50
+ def method_missing(s, *a, &b)
51
+ @self.__send__(s, *a, &b)
52
+ end
53
+
50
54
  end
51
55
 
52
56
  end
53
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dci
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-07 00:00:00.000000000 Z
12
+ date: 2012-02-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: detroit
16
- requirement: &12149120 !ruby/object:Gem::Requirement
16
+ requirement: &12937320 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *12149120
24
+ version_requirements: *12937320
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: qed
27
- requirement: &12148360 !ruby/object:Gem::Requirement
27
+ requirement: &12935480 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *12148360
35
+ version_requirements: *12935480
36
36
  description: Faithful DCI framework for Ruby application development.
37
37
  email:
38
38
  - transfire@gmail.com
@@ -54,7 +54,7 @@ files:
54
54
  - COPYING.md
55
55
  - HISTORY.md
56
56
  - README.md
57
- homepage: https://rubyworks.github.com/dci
57
+ homepage: http://rubyworks.github.com/dci
58
58
  licenses:
59
59
  - BSD-2-Clause
60
60
  post_install_message: