composite_task 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|