Permalink
Browse files

new patterns

  • Loading branch information...
1 parent 7975135 commit d1d07263b86fe3bf8a9073fe995840047f6cfb11 @shvets committed Feb 27, 2011
Showing with 543 additions and 85 deletions.
  1. +8 −7 .idea/design_patterns_in_ruby.iml
  2. +1 −1 .idea/misc.xml
  3. +115 −77 .idea/workspace.xml
  4. +94 −0 enterprise/dci1.rb
  5. +101 −0 enterprise/dci2.rb
  6. +161 −0 enterprise/dsl11.rb
  7. +63 −0 enterprise/dsl13.rb
@@ -4,13 +4,14 @@
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
- <orderEntry type="library" scope="PROVIDED" name="[gem] rcov (v0.9.8, /Users/oshvets/.rvm/gems/ruby-1.8.7-p299/gems/rcov-0.9.8)" level="application" />
- <orderEntry type="library" scope="PROVIDED" name="[gem] columnize (v0.3.1, /Users/oshvets/.rvm/gems/ruby-1.8.7-p299/gems/columnize-0.3.1)" level="application" />
- <orderEntry type="library" scope="PROVIDED" name="[gem] linecache (v0.43, /Users/oshvets/.rvm/gems/ruby-1.8.7-p299/gems/linecache-0.43)" level="application" />
- <orderEntry type="library" scope="PROVIDED" name="[gem] rake (v0.8.7, /Users/oshvets/.rvm/gems/ruby-1.8.7-p299@global/gems/rake-0.8.7)" level="application" />
- <orderEntry type="library" scope="PROVIDED" name="[gem] ruby-debug (v0.10.3, /Users/oshvets/.rvm/gems/ruby-1.8.7-p299/gems/ruby-debug-0.10.3)" level="application" />
- <orderEntry type="library" scope="PROVIDED" name="[gem] ruby-debug-base (v0.10.3, /Users/oshvets/.rvm/gems/ruby-1.8.7-p299@global/gems/ruby-debug-base-0.10.3)" level="application" />
- <orderEntry type="library" scope="PROVIDED" name="[gem] ruby-debug-ide (v0.4.9, /Users/oshvets/.rvm/gems/ruby-1.8.7-p299/gems/ruby-debug-ide-0.4.9)" level="application" />
+ <orderEntry type="library" scope="PROVIDED" name="[gem] mixology (v0.2.0, /Users/oshvets/.rvm/gems/ruby-1.8.7-p334@proteus/gems/mixology-0.2.0)" level="application" />
+ <orderEntry type="library" name="[gem] rcov (v0.9.8, null)" level="application" />
+ <orderEntry type="library" name="[gem] columnize (v0.3.1, null)" level="application" />
+ <orderEntry type="library" scope="PROVIDED" name="[gem] linecache (v0.43, /Users/oshvets/.rvm/gems/ruby-1.8.7-p334@proteus/gems/linecache-0.43)" level="application" />
+ <orderEntry type="library" scope="PROVIDED" name="[gem] rake (v0.8.7, /Users/oshvets/.rvm/gems/ruby-1.8.7-p334@global/gems/rake-0.8.7)" level="application" />
+ <orderEntry type="library" name="[gem] ruby-debug (v0.10.3, null)" level="application" />
+ <orderEntry type="library" name="[gem] ruby-debug-base (v0.10.3, null)" level="application" />
+ <orderEntry type="library" name="[gem] ruby-debug-ide (v0.4.9, null)" level="application" />
</component>
</module>
View
@@ -6,7 +6,7 @@
<component name="ProjectDetails">
<option name="projectName" value="design_patterns_in_ruby" />
</component>
- <component name="ProjectRootManager" version="2" project-jdk-name="Ruby SDK 1.8.7 (2)" project-jdk-type="RUBY_SDK" />
+ <component name="ProjectRootManager" version="2" project-jdk-name="Ruby SDK 1.8.7-p334 [proteus]" project-jdk-type="RUBY_SDK" />
<component name="SvnBranchConfigurationManager">
<option name="mySupportsUserInfoFilter" value="true" />
</component>
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,94 @@
+# dci1.rb
+# Data-Context-Interaction pattern
+
+# The code for separate use case in OO is typically spread out between lots of differen classes.
+# To understand how the code works, you must also know the relationships between objects in runtime.
+# These relationships aren't set in code, they depend on the situation.
+# What DCI proposes is that code for a given use-case is separated out from the classes and put into
+# a different artifact called context. Objects of different classes can enter into a relationship in this
+# context and take part in interaction where they have different roles.
+
+# Suggestions:
+#
+# a) keep core model classes very thin
+# b) keep additional logic/behaviour in roles
+# c) do not do class oriented programming, do object oriented programming
+
+# 1. Data
+class DataObject # thin data/model
+ attr_accessor :basic_property
+end
+
+# 2. Roles: broken into pieces functionality
+module Role1
+ attr_accessor :role1_property
+end
+
+module Role2
+ attr_accessor :role2_property
+end
+
+# 3. The place where role is assigned to data/model.
+# We do it dynamically at run-time, on object, not class declaration level.
+
+class Context # or use case
+ def initialize data
+ @data = data
+ end
+
+ def execute
+ p @data.basic_property # OK
+
+ begin
+ @data.role1_property
+ rescue
+ p "Error: role1_property is not available yet"
+ end
+
+ @data.extend Role1
+
+ @data.role1_property = "test_role1"
+ p @data.role1_property
+ end
+end
+
+class UseCase # or context
+ def initialize data
+ @data = data
+ end
+
+ def execute
+ p @data.basic_property # OK
+
+ begin
+ @data.role2_property
+ rescue
+ p "Error: role2_property is not available yet"
+ end
+
+ @data.extend Role2
+
+ @data.role2_property = "test_role2"
+ p @data.role2_property
+ end
+end
+
+# 4. Actual Program
+
+class Interaction
+ def initialize
+ @data = DataObject.new
+ @data.basic_property = "test_basic"
+ end
+
+ def interact
+ context = Context.new @data
+ context.execute
+
+ use_case = UseCase.new @data
+ use_case.execute
+ end
+end
+
+interaction = Interaction.new
+interaction.interact
View
@@ -0,0 +1,101 @@
+# dci2.rb
+# Data-Context-Interaction pattern
+
+require 'rubygems'
+require 'mixology'
+
+# 1. Data (or model)
+class DataObject # thin data/model
+ attr_accessor :basic_property
+end
+
+# 2. Roles: broken into pieces functionality
+module Role1
+ attr_accessor :role1_property
+end
+
+module Role2
+ attr_accessor :role2_property
+end
+
+# 3. The place where role is assigned to data/model.
+# We do it dynamically at run-time, on object, not class declaration level.
+
+class Context # or use case (or controller)
+ def initialize data
+ @data = data
+ end
+
+ def execute
+ p @data.basic_property # OK
+
+ begin
+ @data.role1_property
+ rescue
+ p "Error: role1_property is not available yet"
+ end
+
+ @data.mixin Role1
+
+ @data.role1_property = "test_role1"
+ p @data.role1_property
+
+ @data.unmix Role1
+
+ begin
+ @data.role1_property
+ rescue
+ p "Error: role1_property is not available again"
+ end
+
+ end
+end
+
+class UseCase # or context
+ def initialize data
+ @data = data
+ end
+
+ def execute
+ p @data.basic_property # OK
+
+ begin
+ @data.role2_property
+ rescue
+ p "Error: role2_property is not available yet"
+ end
+
+ @data.mixin Role2
+
+ @data.role2_property = "test_role2"
+ p @data.role2_property
+
+ @data.unmix Role2
+
+ begin
+ @data.role2_property
+ rescue
+ p "Error: role2_property is not available again"
+ end
+ end
+end
+
+# 4. Actual Program
+
+class Interaction
+ def initialize
+ @data = DataObject.new
+ @data.basic_property = "test_basic"
+ end
+
+ def interact
+ context = Context.new @data
+ context.execute
+
+ use_case = UseCase.new @data
+ use_case.execute
+ end
+end
+
+interaction = Interaction.new
+interaction.interact
View
@@ -0,0 +1,161 @@
+# dsl11.rb
+
+# Domain Specific Language (DSL) is simple set of commands for serving a specific domain.
+# It could be implemented on object or class level. With object level we've got DSL scripts, with
+# the class level - meta-programming statements
+
+# This implementation uses object level.
+
+# 1. Defines DSL elements: tree, trunk, branch, root, leaf.
+# If one element appears inside another, use collection and don't forget to eval
+# incoming block for the parent.
+
+module HasName
+ attr_reader :name
+
+ def initialize(name = '')
+ @name = name
+ end
+
+ def to_s
+ "[name: #{name}]"
+ end
+end
+
+class Leaf
+ include HasName
+
+ def to_s
+ "Leaf[name: #{name}]"
+ end
+end
+
+class Branch
+ include HasName
+
+ attr_reader :leaves
+
+ def initialize name
+ super
+
+ @leaves = []
+ end
+
+ def leaf(name, &block)
+ leaf = Leaf.new(name)
+ leaf.instance_eval(&block) if block_given?
+
+ @leaves << leaf
+
+ leaf
+ end
+
+ def to_s
+ "Branch[name: #{name}; leaves: #{leaves.join(', ')}]"
+ end
+end
+
+class Root
+ include HasName
+
+ def to_s
+ "Root[name: #{name}]"
+ end
+end
+
+class Trunk
+ include HasName
+
+ attr_reader :branches, :roots
+
+ def initialize
+ super
+
+ @branches = []
+ @roots = []
+ end
+
+ def branch(name, &block)
+ branch = Branch.new(name)
+ branch.instance_eval(&block) if block_given?
+
+ @branches << branch
+
+ branch
+ end
+
+ def root(name, &block)
+ root = Root.new(name)
+ root.instance_eval(&block) if block_given?
+
+ @roots << root
+
+ root
+ end
+
+ def to_s
+ " Trunk[\n" +
+ " branches: #{branches.join(', ')};\n" +
+ " roots: #{roots.join(', ')};\n" +
+ " ]"
+ end
+end
+
+class Tree
+ include HasName
+
+ def initialize name
+ super
+ @trunk = Trunk.new
+ end
+
+ def type(type)
+ @type = type
+ end
+
+ def trunk(&block)
+ @trunk.instance_eval(&block)
+ end
+
+ def to_s
+ "Tree [\n name: #{name};\n type: #{@type};\n trunk: #{@trunk}\n]"
+ end
+end
+
+# 2. Defines DSL for describing the tree. It acts as the tree builder.
+
+module Tree::DSL
+ def tree(name, &block)
+ tree = Tree.new(name)
+ tree.instance_eval(&block)
+
+ tree
+ end
+end
+
+# 3. test
+
+include Tree::DSL
+
+# tree description
+
+tree :my_favorite_tree do
+ type :oak
+
+ trunk do
+ branch :b1 do
+ leaf :l1
+ leaf :l2
+ end
+
+ branch :b2 do
+ leaf :l3
+ end
+
+ root :r1
+ root :r2
+ end
+
+ puts self # prints the tree
+end
+
Oops, something went wrong.

0 comments on commit d1d0726

Please sign in to comment.