dci 0.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.
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: []