composite_task 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cf0b99f705295dcf7ccdfd879b5d2f5305a231fb
4
+ data.tar.gz: 4c044311656cf9df4ee077d35a6d0e706ccbbdb3
5
+ SHA512:
6
+ metadata.gz: 73e42f649a10568aee5e70932591b3580fb9a1f6940fbdb6e4c6326cf34a1b450bbc51bf01b16a4f30a0d56539e1f9b70f47fdbbf5000ffe982d4c0eeeab0efe
7
+ data.tar.gz: 506fb9b0b76856e9dcc27bc388cf1480d233266261631ee6a077f66731b139a16a1e46a602db6be9f0c8726049a4230955186b53d2e69435b5c630bdc0d696ad
data/README.md ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ class CompositeTask
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,175 @@
1
+ # Simple implementation of GoF Composite pattern.
2
+ class CompositeTask
3
+
4
+ # Task name (can be nil for top level task).
5
+ attr_reader :name
6
+
7
+ # Array of all CompositeTask instances that compose this Task
8
+ attr_reader :sub_tasks
9
+
10
+ # Task action (ie: given block). Can be nil for grouping only tasks.
11
+ attr_reader :action
12
+
13
+ # IO like object where to write progress to.
14
+ attr_reader :io
15
+
16
+ # Creates a new CompositeTask, and can be used in several fashions.
17
+ #
18
+ # For an ananymous top level class:
19
+ # task = CompositeTask.new()
20
+ # For a named task:
21
+ # task = CompositeTask.new("Task witohut action")
22
+ # For a named task, with an action block:
23
+ # task = CompositeTask.new("Task with action") do |task|
24
+ # puts "Executing action for #{task.name}"
25
+ # end
26
+ # Once created, you can compose your task with #add_sub_task and then #execute it.
27
+ #
28
+ # Progress reporting is done to given io. can be set to nil to disable reporting.
29
+ # :call-seq:
30
+ # initialize()
31
+ # initialize(nil, io=STDOUT)
32
+ # initialize(name, io=STDOUT)
33
+ # initialize(name, io=STDOUT) {|task| ... }
34
+ def initialize(name=nil, io=STDOUT, &action)
35
+ @name = name
36
+ @io = io
37
+ @action = action
38
+ if action && !name
39
+ raise ArgumentError.new('Anonymous tasks are only allowed without a block.')
40
+ end
41
+ @sub_tasks = []
42
+ end
43
+
44
+ # Adds a new sub task directly, or by passing its arguments (same as \#initialize).
45
+ # :call-seq:
46
+ # add_sub_task(task)
47
+ # add_sub_task(name) {|task| ... }
48
+ def add_sub_task(task_or_name, &action)
49
+ if task_or_name.kind_of?(self.class)
50
+ sub_tasks << task_or_name
51
+ else
52
+ sub_tasks << self.class.new(task_or_name, &action)
53
+ end
54
+ end
55
+
56
+ # Adds a sub task without an action defined. Yields newly created task, so it can be used to compose the task:
57
+ # task.add_group("Group of tasks") do |g|
58
+ # g.add_task('task1') { puts 'from task1 inside group' }
59
+ # g.add_task('task2') { puts 'from task2 inside group' }
60
+ # end
61
+ def add_group name # :yields: sub_task
62
+ sub_tasks << ( sub_task = self.class.new(name) )
63
+ yield sub_task
64
+ self
65
+ end
66
+
67
+ # Execute all added sub tasks (#sub_tasks) in order, then execute itself (#call_action).
68
+ # :call-seq:
69
+ # execute()
70
+ def execute(indent = 0)
71
+ if leaf?
72
+ call_action(indent)
73
+ else
74
+ write_bright("#{' ' * indent}#{name}\n") if name
75
+ increment = name ? 1 : 0
76
+ sub_tasks.each do |task|
77
+ task.execute(indent + increment)
78
+ end
79
+ call_action(indent + increment)
80
+ end
81
+ end
82
+
83
+ # Whether it has sub tasks.
84
+ def leaf?
85
+ sub_tasks.empty?
86
+ end
87
+
88
+ # Total number tasks with action that compose this task (exclude "grouping only" tasks).
89
+ def length
90
+ sub_tasks.reduce(action ? 1 : 0) {|acc, sub_task| acc + sub_task.length}
91
+ end
92
+ alias_method :size, :length
93
+
94
+ # All tasks that self is composed (including self).
95
+ # :call-seq:
96
+ # tasks -> Enumerator
97
+ # tasks {|task| ... }
98
+ def tasks &block
99
+ return to_enum(__method__) unless block_given?
100
+ yield self
101
+ sub_tasks.each do |sub_task|
102
+ sub_task.tasks(&block)
103
+ end
104
+ end
105
+
106
+ # Whether self has an action.
107
+ def has_action?
108
+ !!action
109
+ end
110
+
111
+ # All tasks that self is composed (including self), only includen the ones where #has_action? is true.
112
+ # :call-seq:
113
+ # tasks -> Enumerator
114
+ # tasks {|task| ... }
115
+ def tasks_with_action
116
+ return to_enum(__method__) unless block_given?
117
+ tasks.each do |task|
118
+ yield task if task.has_action?
119
+ end
120
+ end
121
+
122
+ # Returns the first task with action with given name.
123
+ def [] name
124
+ tasks_with_action.select{|s| s.name == name}.first
125
+ end
126
+
127
+ # Execute self action only, without executing any of its sub tasks.
128
+ # :call-seq: call_action
129
+ def call_action indent = 0
130
+ if action
131
+ write_bright "#{' ' * indent}#{name}... "
132
+ begin
133
+ @action.call(self)
134
+ rescue
135
+ write_red "[FAIL]\n"
136
+ raise $!
137
+ else
138
+ write_green "[OK]\n"
139
+ end
140
+ else
141
+ if leaf?
142
+ raise RuntimeError.new("Leaf #{name ? "\"#{name}\" " : nil}with undefined action is not allowed.")
143
+ end
144
+ end
145
+ end
146
+
147
+ private
148
+
149
+ ANSI_RESET = "\e[0m"
150
+ ANSI_ATTR_BRIGHT = "\e[1m"
151
+ ANSI_FG_GREEN = "\e[32m"
152
+ ANSI_FG_RED = "\e[31m"
153
+
154
+ def colorize attribute, message
155
+ return unless io
156
+ if io.tty?
157
+ io.write "#{ANSI_RESET}#{Object.const_get("#{self.class}::ANSI_#{attribute.to_s.upcase}")}#{message}#{ANSI_RESET}"
158
+ else
159
+ io.write message
160
+ end
161
+ end
162
+
163
+ def write_bright message
164
+ colorize(:attr_bright, message)
165
+ end
166
+
167
+ def write_green message
168
+ colorize(:fg_green, message)
169
+ end
170
+
171
+ def write_red message
172
+ colorize(:fg_red, message)
173
+ end
174
+
175
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: composite_task
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Fabio Pugliese Ornellas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10.4'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '10.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gem_polisher
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.4'
41
+ description: This Gem implement GoF's Composite pattern for Ruby. It comes with some
42
+ helper methods, and can generate progress output (even colored for terminal).
43
+ email: fabio.ornellas@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files:
47
+ - README.md
48
+ files:
49
+ - README.md
50
+ - lib/composite_task.rb
51
+ - lib/composite_task/version.rb
52
+ homepage: https://github.com/fornellas/composite_task
53
+ licenses: []
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options:
57
+ - "--main"
58
+ - README.md
59
+ - lib/
60
+ - README.md
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 2.4.5.1
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: Gang of Four Composite Design Pattern Implementation (with goodies)
79
+ test_files: []