dci 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.ruby ADDED
@@ -0,0 +1,43 @@
1
+ ---
2
+ source:
3
+ - Profile
4
+ authors:
5
+ - name: Thomas Sawyer
6
+ email: transfire@gmail.com
7
+ copyrights:
8
+ - holder: Thomas Sawyer
9
+ year: '2012'
10
+ license: BSD-2-Clause
11
+ replacements: []
12
+ alternatives: []
13
+ requirements:
14
+ - name: detroit
15
+ groups:
16
+ - build
17
+ development: true
18
+ - name: qed
19
+ groups:
20
+ - test
21
+ development: true
22
+ dependencies: []
23
+ conflicts: []
24
+ repositories:
25
+ - uri: git@github.com:rubyworks/dci.git
26
+ scm: git
27
+ name: upstream
28
+ resources:
29
+ home: https://rubyworks.github.com/dci
30
+ code: https://github.com/rubyworks/dci
31
+ mail: http://groups.google.com/groups/rubyworks-mailinglist
32
+ extra: {}
33
+ load_path:
34
+ - lib
35
+ revision: 0
36
+ version: 0.1.0
37
+ name: dci
38
+ title: DCI
39
+ summary: DCI for Ruby
40
+ created: '2011-03-04'
41
+ description: Faithful DCI framework for Ruby application development.
42
+ organization: Rubyworks
43
+ date: '2012-02-07'
@@ -0,0 +1,7 @@
1
+ --title "DCI"
2
+ --readme README.md
3
+ --protected
4
+ --private
5
+ lib
6
+ -
7
+ [A-Z]*.*
@@ -0,0 +1,36 @@
1
+ # COPYRIGHT
2
+
3
+ ## NOTICES
4
+
5
+ ### Assay
6
+
7
+ | Project | Assay |
8
+ |-----------|-----------------------------------|
9
+ | Copyright | (c) 2012 Rubyworks |
10
+ | License | (r) BSD-2-Clause |
11
+ | Website | http://rubyworks.github.com/assay |
12
+
13
+ ## LICENSES
14
+
15
+ ### BSD-2-Clause License
16
+
17
+ Redistribution and use in source and binary forms, with or without
18
+ modification, are permitted provided that the following conditions are met:
19
+
20
+ 1. Redistributions of source code must retain the above copyright notice,
21
+ this list of conditions and the following disclaimer.
22
+
23
+ 2. Redistributions in binary form must reproduce the above copyright
24
+ notice, this list of conditions and the following disclaimer in the
25
+ documentation and/or other materials provided with the distribution.
26
+
27
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
28
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30
+ COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
34
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,10 @@
1
+ # HISTORY
2
+
3
+ ## 0.1.0 | 2012-02-07
4
+
5
+ This is the initial working version of DCI.
6
+
7
+ Changes:
8
+
9
+ * Happy Birthday!
10
+
@@ -0,0 +1,32 @@
1
+ # DCI for Ruby
2
+
3
+ [Home](http://rubyworks.github.com/dci) /
4
+ [Code](http://github.com/rubyworks/dci) /
5
+ [Bugs](http://github.com/rubyworks/dci/issues) /
6
+ [Mail](http://groups.google.com/groups/rubyworks-mailinglist)
7
+
8
+
9
+ ## Description
10
+
11
+ The DCI library for Ruby is a fairly faithful implementation of the DCI
12
+ concpets developed by Trygve Reenskaug, Reenskaug and James O. Coplien.
13
+
14
+ It define two reusable base classes, the Role and Context. The best way
15
+ to understand their usage is to look at the QED documentation provided
16
+ ([for example](https://github.com/rubyworks/dci/blob/master/demo/account_example.md)).
17
+
18
+
19
+ ## Installation
20
+
21
+ The ususal RubyGems install procedure:
22
+
23
+ $ gem install dci
24
+
25
+
26
+ ## Copyrights
27
+
28
+ Copyright (c) 2012 Rubyworks. All rights reserved.
29
+
30
+ DCI for Ruby is distributable under the terms of **BSD-2-Clause** license.
31
+
32
+ See COPYING.md file for license details.
@@ -0,0 +1,74 @@
1
+ # Account Balance Transfer
2
+
3
+ The Account Balance Transfre is the classic example of using DCI.
4
+
5
+ First we need our Data model. In the example that is the Account class.
6
+ To keep our example simple we will initialize new accounts with
7
+ a balance of $100. (We're generous like that.)
8
+
9
+ class Account
10
+ def initialize(account_id)
11
+ @account_id = account_id
12
+ @balance = 100
13
+ end
14
+ def account_id
15
+ @account_id
16
+ end
17
+ def available_balance
18
+ @balance
19
+ end
20
+ def increase_balance(amount)
21
+ @balance += amount
22
+ end
23
+ def decrease_balance(amount)
24
+ @balance -= amount
25
+ end
26
+ end
27
+
28
+ We set up two Roles, one role for withdrawing money from an account,
29
+ and one for depositing money into an account.
30
+
31
+ class Account::TransferWithdraw < Role
32
+ def transfer(amount)
33
+ decrease_balance(amount)
34
+ #log "Tranfered $#{amount} from account ##{account_id}."
35
+ end
36
+ end
37
+
38
+ class Account::TransferDeposit < Role
39
+ def transfer(amount)
40
+ increase_balance(amount)
41
+ #log "Tranfered $#{amount} into account ##{account_id}."
42
+ end
43
+ end
44
+
45
+ Now we create a Context which will assign accounts to the roles
46
+ and used to perfomr the transfer.
47
+
48
+ # We can think of a context as setting a scene.
49
+ class Account::Transfer < Context
50
+ role :source_account => Account::TransferWithdraw
51
+ role :destination_account => Account::TransferDeposit
52
+
53
+ def initialize(source_account, destination_account)
54
+ self.source_account = source_account
55
+ self.destination_account = destination_account
56
+ end
57
+
58
+ def transfer(amount)
59
+ #log "Begin transfer."
60
+ roles.each{ |role| role.transfer(amount) }
61
+ #log "Transfer complete."
62
+ end
63
+ end
64
+
65
+ Let's give it a try.
66
+
67
+ acct1 = Account.new(000100)
68
+ acct2 = Account.new(000200)
69
+
70
+ Account::Transfer.new(acct1, acct2).transfer(50)
71
+
72
+ acct1.available_balance #=> 50
73
+ acct2.available_balance #=> 150
74
+
@@ -0,0 +1 @@
1
+ require 'dci'
@@ -0,0 +1,38 @@
1
+ # Data, Context and Interaction (DCI) is a paradigm used in computer software to
2
+ # program systems of communicating objects. Its goals are:
3
+ #
4
+ # * To improve the readability of object-oriented code by giving system behavior
5
+ # first-class status;
6
+ #
7
+ # * To cleanly separate code for rapidly changing system behavior (what the system does)
8
+ # from code for slowly changing domain knowledge (what the system is), instead
9
+ # of combining both in one class interface;
10
+ #
11
+ # * To help software developers reason about system-level state and behavior
12
+ # instead of only object state and behavior;
13
+ #
14
+ # * To support an object style of thinking that is close to peoples' mental
15
+ # models, rather than the class style of thinking that overshadowed object
16
+ # thinking early in the history of object-oriented programming languages.
17
+ #
18
+ # The paradigm separates the domain model (data) from use cases (context) and roles
19
+ # that objects play (interaction). DCI is complementary to model–view–controller (MVC).
20
+ # MVC as a pattern language is still used to separate the data and its processing from
21
+ # presentation.
22
+ #
23
+ # DCI was invented by Trygve Reenskaug, also the inventor of MVC. The current formulation
24
+ # of DCI is mostly the work of Reenskaug and James O. Coplien.
25
+ #
26
+ # acct1 = Account.new(10500)
27
+ # acct2 = Account.new(10010)
28
+ #
29
+ # Balance::Transfer.new(acct1, acct2).transfer(50)
30
+ #
31
+ module DCI
32
+ end
33
+
34
+ require 'dci/object' # data
35
+ require 'dci/context' # context
36
+ require 'dci/role' # interation
37
+
38
+
@@ -0,0 +1,89 @@
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
48
+
49
+ # Define a role given the name the role will use in this context,
50
+ # and the role class that is to be played.
51
+ #
52
+ def self.role(name_to_role)
53
+ name_to_role.each do |name, role|
54
+ define_method("role_#{name}"){ role }
55
+
56
+ module_eval %{
57
+ def #{name}=(data)
58
+ @#{name} = role_#{name}.new(data)
59
+ end
60
+
61
+ def #{name}
62
+ @#{name}
63
+ end
64
+ }
65
+ end
66
+ end
67
+
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)
74
+ end
75
+ end
76
+
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_',''))
85
+ end
86
+ list
87
+ end
88
+
89
+ end
@@ -0,0 +1,47 @@
1
+ # Data - The data are "what the system is." The data part of the DCI architecture
2
+ # is its (relatively) static data model with relations. The data design is usually
3
+ # coded up as conventional classes that represent the basic domain structure of
4
+ # the system. These classes are barely smart data, and they explicitly lack the
5
+ # functionality that is peculiar to support of any particular use case. These
6
+ # classes commonly encapsulate the physical storage of the data. These data
7
+ # implement an information structure that comes from the mental model of end
8
+ # users, domain experts, programmers, and other people in the system. They may
9
+ # correspond closely to the model objects of MVC.
10
+ #
11
+ # An example of a data object could be a bank account. Its interface would have
12
+ # basic operations for increasing and decreasing the balance and for inquiring
13
+ # about the current balance. The interface would likely not offer operations that
14
+ # involve transactions, or which in any way involve other objects or any user
15
+ # interaction. So, for example, while a bank account may offer a primitive for
16
+ # increasing the balance, it would have no method called deposit. Such operations
17
+ # belong instead in the interaction part of DCI.
18
+ #
19
+ # Data objects are instances of classes that might come from domain-driven design,
20
+ # and such classes might use subtyping relationships to organize domain data.
21
+ # Though it reduces to classes in the end, DCI reflects a computational model
22
+ # dominated by object thinking rather than class thinking. Therefore, when
23
+ # thinking "data" in DCI, it means thinking more about the instances at run time
24
+ # than about the classes from which they were instantiated.
25
+ #
26
+ # class Account
27
+ # def initialize(accountId)
28
+ # @account_id = accountId
29
+ # @balance = 0
30
+ # end
31
+ # def account_id
32
+ # @account_id
33
+ # end
34
+ # def available_balance
35
+ # @balance
36
+ # end
37
+ # def increase_balance(amount)
38
+ # @balance += amount
39
+ # end
40
+ # def decrease_balance(amount)
41
+ # @balance -= amount
42
+ # end
43
+ # end
44
+ #
45
+ # @todo Should objects track the roles in which they are presently particiapting?
46
+ class Object
47
+ end
@@ -0,0 +1,53 @@
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
40
+
41
+ #
42
+ def initialize(player)
43
+ @self = player
44
+ end
45
+
46
+ #
47
+ # @todo Should use #public_send?
48
+ def method_missing(s, *a, &b)
49
+ @self.__send__(s, *a, &b)
50
+ end
51
+
52
+ end
53
+
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dci
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Thomas Sawyer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: detroit
16
+ requirement: &12149120 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *12149120
25
+ - !ruby/object:Gem::Dependency
26
+ name: qed
27
+ requirement: &12148360 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *12148360
36
+ description: Faithful DCI framework for Ruby application development.
37
+ email:
38
+ - transfire@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files:
42
+ - COPYING.md
43
+ - HISTORY.md
44
+ - README.md
45
+ files:
46
+ - .ruby
47
+ - .yardopts
48
+ - demo/account_example.md
49
+ - demo/applique/dci.rb
50
+ - lib/dci/context.rb
51
+ - lib/dci/object.rb
52
+ - lib/dci/role.rb
53
+ - lib/dci.rb
54
+ - COPYING.md
55
+ - HISTORY.md
56
+ - README.md
57
+ homepage: https://rubyworks.github.com/dci
58
+ licenses:
59
+ - BSD-2-Clause
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 1.8.11
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: DCI for Ruby
82
+ test_files: []