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 +7 -0
- data/README.md +0 -0
- data/lib/composite_task/version.rb +3 -0
- data/lib/composite_task.rb +175 -0
- metadata +79 -0
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,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: []
|