ccp 0.1.2 → 0.1.3
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/README.rdoc +111 -0
- data/ccp.gemspec +1 -1
- data/lib/ccp.rb +1 -0
- data/lib/ccp/commands/composite.rb +5 -12
- data/lib/ccp/commands/executable.rb +2 -2
- data/lib/ccp/commands/receivable.rb +1 -1
- data/lib/ccp/invokers/base.rb +28 -5
- data/lib/ccp/receivers.rb +1 -1
- data/lib/ccp/receivers/global.rb +9 -0
- data/lib/ccp/receivers/none.rb +1 -1
- data/lib/ccp/receivers/profileable.rb +8 -4
- data/lib/ccp/version.rb +1 -1
- data/spec/commands_composite_spec.rb +83 -0
- data/spec/commands_core_spec.rb +47 -0
- data/spec/invokers_spec.rb +121 -0
- data/spec/models.rb +98 -0
- data/spec/spec_helper.rb +2 -0
- metadata +13 -11
- data/README +0 -0
- data/lib/ccp/commands/runtime_args.rb +0 -24
- data/spec/commands_spec.rb +0 -18
- data/spec/composite_spec.rb +0 -85
data/README.rdoc
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
= ccp
|
2
|
+
|
3
|
+
CCP is a Ruby library for Composite Command Programming
|
4
|
+
that helps you to split spaghetti codes into pieces.
|
5
|
+
|
6
|
+
=== Websites
|
7
|
+
* http://github.com/maiha/ccp
|
8
|
+
|
9
|
+
== What is a Composite Command Programming?
|
10
|
+
|
11
|
+
There are three principles.
|
12
|
+
|
13
|
+
1. SRP (Single responsibility principle)
|
14
|
+
2. Typed Variables (especially needed in Ruby)
|
15
|
+
3. Explicit Data Dependencies
|
16
|
+
|
17
|
+
As you know, Ruby is a handy and powerful programming language.
|
18
|
+
We can use variables without definitions and re-assign them even if type mismatch.
|
19
|
+
Although it is very comfortable while you are writing, it would be painful for others.
|
20
|
+
|
21
|
+
CCP is a framework composed with above principles and a few debugging utils
|
22
|
+
that gives you(as writer) a little restrictions and gives you(as reader) a readability.
|
23
|
+
|
24
|
+
|
25
|
+
== Example
|
26
|
+
=== usual ruby code
|
27
|
+
|
28
|
+
class SomeOperation
|
29
|
+
def execute
|
30
|
+
# fetching data
|
31
|
+
# calculating it
|
32
|
+
# print results
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Later, it would be a more complex and longer code like this.
|
37
|
+
|
38
|
+
class SomeOperation
|
39
|
+
def execute
|
40
|
+
@data = fetch_data
|
41
|
+
...
|
42
|
+
@result = calculate(@data)
|
43
|
+
...
|
44
|
+
print_results(@result)
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetching_data
|
48
|
+
# accessing instance variables, and long code here
|
49
|
+
...
|
50
|
+
|
51
|
+
Let's imagine a situation that you need to replace above "fetch" code after several years.
|
52
|
+
It is too hard to see data dependencies especially about instance variables.
|
53
|
+
|
54
|
+
=== with CCP
|
55
|
+
|
56
|
+
class SomeOperation
|
57
|
+
include Ccp::Commands::Composite
|
58
|
+
|
59
|
+
command FetchData
|
60
|
+
command Calculate
|
61
|
+
command PrintResult
|
62
|
+
end
|
63
|
+
|
64
|
+
class FetchData # 1. SRP
|
65
|
+
include Ccp::Commands::Core
|
66
|
+
|
67
|
+
# {pre,post} methods can be used like Design By Contract
|
68
|
+
def post
|
69
|
+
data.check(:fetched, {Symbol => [Float]}) # 2. Typed Variables
|
70
|
+
end
|
71
|
+
|
72
|
+
def execute
|
73
|
+
# fetching data...
|
74
|
+
data[:fetched] = ... # 3. Data Dependencies
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Calculate
|
79
|
+
...
|
80
|
+
|
81
|
+
|
82
|
+
All sub commands like FetchData,Calculate,PrintResult are executed
|
83
|
+
in each scopes, and can share variables only via data object.
|
84
|
+
|
85
|
+
So you can easily refactor or replace FetchData unit
|
86
|
+
because there are no implicit instance variable dependencies
|
87
|
+
and futhermore all depencenies would be explicitly declared in "pre","post" method.
|
88
|
+
|
89
|
+
=== execute
|
90
|
+
|
91
|
+
Just call a "execute" instance method.
|
92
|
+
|
93
|
+
cmd = SomeOperation.new
|
94
|
+
cmd.execute
|
95
|
+
|
96
|
+
=== invokers
|
97
|
+
|
98
|
+
Invokers::Base can be used as a top level composite command.
|
99
|
+
|
100
|
+
class SomeOperation < Ccp::Invokers::Base
|
101
|
+
command FetchData
|
102
|
+
...
|
103
|
+
|
104
|
+
|
105
|
+
Its "benchmark" method generates profile information.
|
106
|
+
|
107
|
+
ruby -r some_operation -e 'SomeOperation.new.benchmark'
|
108
|
+
[43.3%] 2.5834830 FetchData#execute
|
109
|
+
[35.9%] 2.0710440 Calculate#execute
|
110
|
+
...
|
111
|
+
|
data/ccp.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.add_dependency "typed", ">= 0.1.
|
21
|
+
s.add_dependency "typed", ">= 0.1.2"
|
22
22
|
s.add_dependency "dsl_accessor", ">= 0.4.0"
|
23
23
|
|
24
24
|
s.add_development_dependency "rspec"
|
data/lib/ccp.rb
CHANGED
@@ -56,12 +56,6 @@ module Ccp
|
|
56
56
|
######################################################################
|
57
57
|
### Enumerable
|
58
58
|
|
59
|
-
def <<(command)
|
60
|
-
command = command.new if command.is_a?(Class) and command.ancestors.include?(Core)
|
61
|
-
command.must(Core)
|
62
|
-
commands << command
|
63
|
-
end
|
64
|
-
|
65
59
|
def commands
|
66
60
|
@commands ||= build_commands.must(Array)
|
67
61
|
end
|
@@ -70,19 +64,18 @@ module Ccp
|
|
70
64
|
### Commands
|
71
65
|
|
72
66
|
def execute
|
73
|
-
benchmark
|
67
|
+
commands.each(&:benchmark)
|
74
68
|
end
|
75
69
|
|
76
|
-
def
|
77
|
-
|
78
|
-
commands.each
|
79
|
-
post if respond_to?(:post)
|
70
|
+
def receiver=(value)
|
71
|
+
super
|
72
|
+
commands.each{|c| c.receiver = value}
|
80
73
|
end
|
81
74
|
|
82
75
|
private
|
83
76
|
def build_commands
|
84
77
|
array = self.class.commands.select{|c| c.cond.nil? or instance_eval(&c.cond)}
|
85
|
-
array.map{|c|
|
78
|
+
cmds = array.map{|c|
|
86
79
|
c = c.klass.new(*c.args)
|
87
80
|
c.receiver = receiver
|
88
81
|
c
|
data/lib/ccp/invokers/base.rb
CHANGED
@@ -12,26 +12,49 @@ module Ccp
|
|
12
12
|
DEFAULT_OPTIONS = {
|
13
13
|
:profile => false,
|
14
14
|
:comment => true,
|
15
|
+
:logger => Logger.new($stderr),
|
15
16
|
}
|
16
17
|
|
18
|
+
######################################################################
|
19
|
+
### Class Methods
|
20
|
+
|
21
|
+
def self.execute(options = {}, &block)
|
22
|
+
cmd = new(options)
|
23
|
+
if block_given?
|
24
|
+
cmd.instance_eval(&block)
|
25
|
+
end
|
26
|
+
cmd.benchmark
|
27
|
+
return cmd
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.benchmark(options = {}, &block)
|
31
|
+
execute({:profile => true}.merge(options), &block)
|
32
|
+
end
|
33
|
+
|
17
34
|
######################################################################
|
18
35
|
### Instance Methods
|
19
36
|
|
20
37
|
def initialize(options = nil)
|
21
|
-
|
22
|
-
|
38
|
+
options ||= {}
|
39
|
+
set_default_receiver(options[:receiver])
|
23
40
|
set_default_options
|
41
|
+
set_runtime_options(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_default_receiver(receiver)
|
45
|
+
self.receiver = receiver || self.class.receiver.new
|
24
46
|
end
|
25
47
|
|
26
48
|
def set_default_options
|
27
49
|
self.class::DEFAULT_OPTIONS.each_pair do |key,val|
|
28
50
|
data.default[key] = val
|
29
51
|
end
|
30
|
-
data.default(:logger) { Logger.new($stderr) }
|
31
52
|
end
|
32
53
|
|
33
|
-
def
|
34
|
-
|
54
|
+
def set_runtime_options(options)
|
55
|
+
options.each_pair do |key,val|
|
56
|
+
data[key] = val
|
57
|
+
end
|
35
58
|
end
|
36
59
|
|
37
60
|
def benchmark
|
data/lib/ccp/receivers.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Ccp
|
2
2
|
module Receivers
|
3
3
|
autoload :Base , 'ccp/receivers/base'
|
4
|
-
autoload :
|
4
|
+
autoload :Global , 'ccp/receivers/global'
|
5
5
|
autoload :Commentable , 'ccp/receivers/commentable'
|
6
6
|
autoload :Profileable , 'ccp/receivers/profileable'
|
7
7
|
end
|
data/lib/ccp/receivers/none.rb
CHANGED
@@ -16,12 +16,16 @@ module Ccp
|
|
16
16
|
|
17
17
|
def profile(target, method)
|
18
18
|
start = Time.new
|
19
|
-
target.pre if target.
|
19
|
+
target.__send__(:pre) if target.respond_to?(:pre)
|
20
20
|
target.__send__(method)
|
21
|
-
target.post if target.
|
22
|
-
|
21
|
+
target.__send__(:post) if target.respond_to?(:post)
|
22
|
+
|
23
|
+
case target
|
24
|
+
when Ccp::Commands::Composite
|
25
|
+
# no profiles
|
26
|
+
else
|
23
27
|
profiles << Profile.new(target, method, (Time.new - start).to_f)
|
24
|
-
|
28
|
+
end
|
25
29
|
end
|
26
30
|
|
27
31
|
def profiles
|
data/lib/ccp/version.rb
CHANGED
@@ -0,0 +1,83 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ccp::Commands::Composite do
|
4
|
+
describe "#execute" do
|
5
|
+
it "should call its execute and sub commands's {pre,execute,post} in declared order" do
|
6
|
+
c = Program.new
|
7
|
+
c.data[:breadcrumbs] = []
|
8
|
+
c.execute
|
9
|
+
c.data[:breadcrumbs].should ==
|
10
|
+
["Cmd1#pre", "Cmd1#execute", "Cmd1#post",
|
11
|
+
"Cmd2#pre", "Cmd2#execute", "Cmd2#post",
|
12
|
+
"Cmd3#pre", "Cmd3#execute", "Cmd3#post"]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#benchmark" do
|
17
|
+
it "should call its and sub commands's {pre,execute,post} in declared order" do
|
18
|
+
c = Program.new
|
19
|
+
c.data[:breadcrumbs] = []
|
20
|
+
c.benchmark
|
21
|
+
c.data[:breadcrumbs].should ==
|
22
|
+
["Program#pre",
|
23
|
+
"Cmd1#pre", "Cmd1#execute", "Cmd1#post",
|
24
|
+
"Cmd2#pre", "Cmd2#execute", "Cmd2#post",
|
25
|
+
"Cmd3#pre", "Cmd3#execute", "Cmd3#post",
|
26
|
+
"Program#post"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "Ccp::Commands::Composite(nested)" do
|
32
|
+
describe "#execute" do
|
33
|
+
it "should call its execute and sub commands's {pre,execute,post} in declared order" do
|
34
|
+
c = CompositeProgram.new
|
35
|
+
c.data[:breadcrumbs] = []
|
36
|
+
c.execute
|
37
|
+
c.data[:breadcrumbs].should ==
|
38
|
+
["Cmd1#pre", "Cmd1#execute", "Cmd1#post",
|
39
|
+
"Cmd23#pre",
|
40
|
+
"Cmd23#execute:start",
|
41
|
+
"Cmd2#pre", "Cmd2#execute", "Cmd2#post",
|
42
|
+
"Cmd3#pre", "Cmd3#execute", "Cmd3#post",
|
43
|
+
"Cmd23#execute:end",
|
44
|
+
"Cmd23#post",
|
45
|
+
"Cmd4#pre", "Cmd4#execute", "Cmd4#post"]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#benchmark" do
|
50
|
+
it "should call its and sub commands's {pre,execute,post} in declared order" do
|
51
|
+
c = CompositeProgram.new
|
52
|
+
c.data[:breadcrumbs] = []
|
53
|
+
c.benchmark
|
54
|
+
c.data[:breadcrumbs].should ==
|
55
|
+
["CompositeProgram#pre",
|
56
|
+
"Cmd1#pre", "Cmd1#execute", "Cmd1#post",
|
57
|
+
"Cmd23#pre",
|
58
|
+
"Cmd23#execute:start",
|
59
|
+
"Cmd2#pre", "Cmd2#execute", "Cmd2#post",
|
60
|
+
"Cmd3#pre", "Cmd3#execute", "Cmd3#post",
|
61
|
+
"Cmd23#execute:end",
|
62
|
+
"Cmd23#post",
|
63
|
+
"Cmd4#pre", "Cmd4#execute", "Cmd4#post",
|
64
|
+
"CompositeProgram#post"]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should update receiver recursively" do
|
69
|
+
cmd = CompositeProgram.new
|
70
|
+
cmd.commands.each do |c|
|
71
|
+
c.receiver.should == cmd.receiver
|
72
|
+
end
|
73
|
+
|
74
|
+
new_receiver = Ccp::Receivers::Base.new
|
75
|
+
new_receiver.should_not == cmd.receiver
|
76
|
+
|
77
|
+
# update receiver
|
78
|
+
cmd.receiver = new_receiver
|
79
|
+
cmd.commands.each do |c|
|
80
|
+
c.receiver.should == cmd.receiver
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ccp::Commands::Core do
|
4
|
+
describe "(accessor)" do
|
5
|
+
subject { Object.new.extend Ccp::Commands::Core }
|
6
|
+
|
7
|
+
# data container
|
8
|
+
it { should respond_to(:data?) }
|
9
|
+
it { should respond_to(:data) }
|
10
|
+
its(:data) { should be_kind_of(Typed::Hash) }
|
11
|
+
|
12
|
+
# executable
|
13
|
+
it { should respond_to(:execute) }
|
14
|
+
it { should respond_to(:benchmark) }
|
15
|
+
|
16
|
+
# receivable
|
17
|
+
it { should respond_to(:receiver) }
|
18
|
+
its(:receiver) { should be_kind_of(Ccp::Receivers::Base) }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#execute" do
|
22
|
+
it "should call only execute" do
|
23
|
+
cmd1 = Cmd1.new
|
24
|
+
cmd1.data[:breadcrumbs] = []
|
25
|
+
cmd1.execute
|
26
|
+
cmd1.data[:breadcrumbs].should == ["Cmd1#execute"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#benchmark" do
|
31
|
+
it "should call {pre,execute,post}" do
|
32
|
+
cmd1 = Cmd1.new
|
33
|
+
cmd1.data[:breadcrumbs] = []
|
34
|
+
cmd1.benchmark
|
35
|
+
cmd1.data[:breadcrumbs].should == ["Cmd1#pre", "Cmd1#execute", "Cmd1#post"]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should call receiver.profile" do
|
39
|
+
(receiver = Ccp::Receivers::Base.new).should_receive(:profile)
|
40
|
+
|
41
|
+
cmd1 = Cmd1.new
|
42
|
+
cmd1.receiver = receiver
|
43
|
+
cmd1.data[:breadcrumbs] = []
|
44
|
+
cmd1.benchmark
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ccp::Invokers::Base do
|
4
|
+
def no_logger; Logger.new('/dev/null'); end
|
5
|
+
|
6
|
+
describe "#execute" do
|
7
|
+
it "should call its execute and sub commands's {pre,execute,post} in declared order" do
|
8
|
+
c = CompositeInvoker.new
|
9
|
+
c.data[:breadcrumbs] = []
|
10
|
+
c.execute
|
11
|
+
c.data[:breadcrumbs].should ==
|
12
|
+
["Cmd1#pre", "Cmd1#execute", "Cmd1#post",
|
13
|
+
"Cmd23#pre",
|
14
|
+
"Cmd23#execute:start",
|
15
|
+
"Cmd2#pre", "Cmd2#execute", "Cmd2#post",
|
16
|
+
"Cmd3#pre", "Cmd3#execute", "Cmd3#post",
|
17
|
+
"Cmd23#execute:end",
|
18
|
+
"Cmd23#post",
|
19
|
+
"Cmd4#pre", "Cmd4#execute", "Cmd4#post"]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#benchmark" do
|
24
|
+
it "should call its and sub commands's {pre,execute,post} in declared order" do
|
25
|
+
c = CompositeInvoker.new
|
26
|
+
c.data[:breadcrumbs] = []
|
27
|
+
c.benchmark
|
28
|
+
c.data[:breadcrumbs].should ==
|
29
|
+
["CompositeInvoker#pre",
|
30
|
+
"Cmd1#pre", "Cmd1#execute", "Cmd1#post",
|
31
|
+
"Cmd23#pre",
|
32
|
+
"Cmd23#execute:start",
|
33
|
+
"Cmd2#pre", "Cmd2#execute", "Cmd2#post",
|
34
|
+
"Cmd3#pre", "Cmd3#execute", "Cmd3#post",
|
35
|
+
"Cmd23#execute:end",
|
36
|
+
"Cmd23#post",
|
37
|
+
"Cmd4#pre", "Cmd4#execute", "Cmd4#post",
|
38
|
+
"CompositeInvoker#post"]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe ".execute" do
|
43
|
+
it "should call its and sub commands's {pre,execute,post} in declared order" do
|
44
|
+
c = CompositeInvoker.execute(:breadcrumbs => [])
|
45
|
+
c.data[:breadcrumbs].should ==
|
46
|
+
["CompositeInvoker#pre",
|
47
|
+
"Cmd1#pre", "Cmd1#execute", "Cmd1#post",
|
48
|
+
"Cmd23#pre",
|
49
|
+
"Cmd23#execute:start",
|
50
|
+
"Cmd2#pre", "Cmd2#execute", "Cmd2#post",
|
51
|
+
"Cmd3#pre", "Cmd3#execute", "Cmd3#post",
|
52
|
+
"Cmd23#execute:end",
|
53
|
+
"Cmd23#post",
|
54
|
+
"Cmd4#pre", "Cmd4#execute", "Cmd4#post",
|
55
|
+
"CompositeInvoker#post"]
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should call only show_comments in default" do
|
59
|
+
r = Ccp::Receivers::Base.new
|
60
|
+
r.should_receive(:show_comments).once
|
61
|
+
r.should_receive(:show_profiles).never
|
62
|
+
CompositeInvoker.execute(:receiver => r, :breadcrumbs => [])
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should call show_profiles if :profile option is given" do
|
66
|
+
r = Ccp::Receivers::Base.new
|
67
|
+
r.should_receive(:show_profiles).once
|
68
|
+
CompositeInvoker.execute(:receiver => r, :breadcrumbs => [], :profile => true)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should disable show_comments if :comment option is false" do
|
72
|
+
r = Ccp::Receivers::Base.new
|
73
|
+
r.should_receive(:show_comments).never
|
74
|
+
CompositeInvoker.execute(:receiver => r, :breadcrumbs => [], :comment => false)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe ".benchmark" do
|
79
|
+
it "should call its and sub commands's {pre,execute,post} in declared order" do
|
80
|
+
r = Ccp::Receivers::Base.new
|
81
|
+
r.stub!(:show_comments) # disable output
|
82
|
+
r.stub!(:show_profiles) # disable output
|
83
|
+
|
84
|
+
c = CompositeInvoker.benchmark(:receiver => r, :breadcrumbs => [])
|
85
|
+
c.data[:breadcrumbs].should ==
|
86
|
+
["CompositeInvoker#pre",
|
87
|
+
"Cmd1#pre", "Cmd1#execute", "Cmd1#post",
|
88
|
+
"Cmd23#pre",
|
89
|
+
"Cmd23#execute:start",
|
90
|
+
"Cmd2#pre", "Cmd2#execute", "Cmd2#post",
|
91
|
+
"Cmd3#pre", "Cmd3#execute", "Cmd3#post",
|
92
|
+
"Cmd23#execute:end",
|
93
|
+
"Cmd23#post",
|
94
|
+
"Cmd4#pre", "Cmd4#execute", "Cmd4#post",
|
95
|
+
"CompositeInvoker#post"]
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should call only show_comments in default" do
|
99
|
+
r = Ccp::Receivers::Base.new
|
100
|
+
r.should_receive(:show_comments).once
|
101
|
+
r.should_receive(:show_profiles).once
|
102
|
+
CompositeInvoker.benchmark(:receiver => r, :breadcrumbs => [])
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should disable show_profiles if :profile option is false" do
|
106
|
+
r = Ccp::Receivers::Base.new
|
107
|
+
r.should_receive(:show_comments).once
|
108
|
+
r.should_receive(:show_profiles).never
|
109
|
+
CompositeInvoker.benchmark(:receiver => r, :breadcrumbs => [], :profile => false)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should disable show_comments if :comment option is false" do
|
113
|
+
r = Ccp::Receivers::Base.new
|
114
|
+
r.should_receive(:show_comments).never
|
115
|
+
r.should_receive(:show_profiles).once
|
116
|
+
CompositeInvoker.benchmark(:receiver => r, :breadcrumbs => [], :comment => false)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
data/spec/models.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
module Breadcrumbing
|
2
|
+
def this
|
3
|
+
"%s#%s" % [self.class.name, caller[0].to_s.scan(/`(.*?)'/).first]
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class Cmd1
|
8
|
+
include Ccp::Commands::Core
|
9
|
+
include Breadcrumbing
|
10
|
+
|
11
|
+
def pre
|
12
|
+
data[:breadcrumbs] << this
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute
|
16
|
+
data[:breadcrumbs] << this
|
17
|
+
end
|
18
|
+
|
19
|
+
def post
|
20
|
+
data[:breadcrumbs] << this
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Cmd2 < Cmd1; end
|
25
|
+
class Cmd3 < Cmd1; end
|
26
|
+
class Cmd4 < Cmd1; end
|
27
|
+
|
28
|
+
class Program
|
29
|
+
include Ccp::Commands::Composite
|
30
|
+
include Breadcrumbing
|
31
|
+
|
32
|
+
command Cmd1
|
33
|
+
command Cmd2
|
34
|
+
command Cmd3
|
35
|
+
|
36
|
+
def pre
|
37
|
+
data[:breadcrumbs] << this
|
38
|
+
end
|
39
|
+
|
40
|
+
def post
|
41
|
+
data[:breadcrumbs] << this
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Cmd23
|
46
|
+
include Ccp::Commands::Composite
|
47
|
+
include Breadcrumbing
|
48
|
+
|
49
|
+
command Cmd2
|
50
|
+
command Cmd3
|
51
|
+
|
52
|
+
def pre
|
53
|
+
data[:breadcrumbs] << this
|
54
|
+
end
|
55
|
+
|
56
|
+
def execute
|
57
|
+
data[:breadcrumbs] << this + ":start"
|
58
|
+
super
|
59
|
+
data[:breadcrumbs] << this + ":end"
|
60
|
+
end
|
61
|
+
|
62
|
+
def post
|
63
|
+
data[:breadcrumbs] << this
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class CompositeProgram
|
68
|
+
include Ccp::Commands::Composite
|
69
|
+
include Breadcrumbing
|
70
|
+
|
71
|
+
command Cmd1
|
72
|
+
command Cmd23
|
73
|
+
command Cmd4
|
74
|
+
|
75
|
+
def pre
|
76
|
+
data[:breadcrumbs] << this
|
77
|
+
end
|
78
|
+
|
79
|
+
def post
|
80
|
+
data[:breadcrumbs] << this
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class CompositeInvoker < Ccp::Invokers::Base
|
85
|
+
include Breadcrumbing
|
86
|
+
|
87
|
+
command Cmd1
|
88
|
+
command Cmd23
|
89
|
+
command Cmd4
|
90
|
+
|
91
|
+
def pre
|
92
|
+
data[:breadcrumbs] << this
|
93
|
+
end
|
94
|
+
|
95
|
+
def post
|
96
|
+
data[:breadcrumbs] << this
|
97
|
+
end
|
98
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ccp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 3
|
10
|
+
version: 0.1.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- maiha
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-02-
|
18
|
+
date: 2012-02-14 00:00:00 +09:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -26,12 +26,12 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 31
|
30
30
|
segments:
|
31
31
|
- 0
|
32
32
|
- 1
|
33
|
-
-
|
34
|
-
version: 0.1.
|
33
|
+
- 2
|
34
|
+
version: 0.1.2
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id001
|
37
37
|
- !ruby/object:Gem::Dependency
|
@@ -76,7 +76,7 @@ extra_rdoc_files: []
|
|
76
76
|
files:
|
77
77
|
- .gitignore
|
78
78
|
- Gemfile
|
79
|
-
- README
|
79
|
+
- README.rdoc
|
80
80
|
- Rakefile
|
81
81
|
- ccp.gemspec
|
82
82
|
- lib/ccp.rb
|
@@ -89,19 +89,21 @@ files:
|
|
89
89
|
- lib/ccp/commands/executable.rb
|
90
90
|
- lib/ccp/commands/receivable.rb
|
91
91
|
- lib/ccp/commands/resolvable.rb
|
92
|
-
- lib/ccp/commands/runtime_args.rb
|
93
92
|
- lib/ccp/data.rb
|
94
93
|
- lib/ccp/invokers.rb
|
95
94
|
- lib/ccp/invokers/base.rb
|
96
95
|
- lib/ccp/receivers.rb
|
97
96
|
- lib/ccp/receivers/base.rb
|
98
97
|
- lib/ccp/receivers/commentable.rb
|
98
|
+
- lib/ccp/receivers/global.rb
|
99
99
|
- lib/ccp/receivers/none.rb
|
100
100
|
- lib/ccp/receivers/profileable.rb
|
101
101
|
- lib/ccp/version.rb
|
102
|
-
- spec/
|
103
|
-
- spec/
|
102
|
+
- spec/commands_composite_spec.rb
|
103
|
+
- spec/commands_core_spec.rb
|
104
104
|
- spec/data_spec.rb
|
105
|
+
- spec/invokers_spec.rb
|
106
|
+
- spec/models.rb
|
105
107
|
- spec/spec_helper.rb
|
106
108
|
has_rdoc: true
|
107
109
|
homepage: http://github.com/maiha/ccp
|
data/README
DELETED
File without changes
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
# map options to data
|
3
|
-
|
4
|
-
module Ccp
|
5
|
-
module Commands
|
6
|
-
class RuntimeArgs
|
7
|
-
include Core
|
8
|
-
|
9
|
-
def initialize(options = {})
|
10
|
-
@options = (options || {}).must(Hash)
|
11
|
-
end
|
12
|
-
|
13
|
-
def execute
|
14
|
-
@options.each_pair do |key, val|
|
15
|
-
data[key] = val
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def inspect
|
20
|
-
super.sub(/>$/, " #{@options.inspect}>")
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/spec/commands_spec.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Ccp::Commands::Core do
|
4
|
-
subject { Object.new.extend Ccp::Commands::Core }
|
5
|
-
|
6
|
-
# data container
|
7
|
-
it { should respond_to(:data?) }
|
8
|
-
it { should respond_to(:data) }
|
9
|
-
its(:data) { should be_kind_of(Typed::Hash) }
|
10
|
-
|
11
|
-
# executable
|
12
|
-
it { should respond_to(:execute) }
|
13
|
-
it { should respond_to(:benchmark) }
|
14
|
-
|
15
|
-
# receivable
|
16
|
-
it { should respond_to(:receiver) }
|
17
|
-
its(:receiver) { should be_kind_of(Ccp::Receivers::Base) }
|
18
|
-
end
|
data/spec/composite_spec.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Ccp::Commands::Composite do
|
4
|
-
module Breadcrumbing
|
5
|
-
BREADCRUMBS = []
|
6
|
-
|
7
|
-
def this
|
8
|
-
"%s#%s" % [self.class.name, caller[0].to_s.scan(/`(.*?)'/).first]
|
9
|
-
end
|
10
|
-
|
11
|
-
def breadcrumbs
|
12
|
-
BREADCRUMBS
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class Cmd1
|
17
|
-
include Ccp::Commands::Core
|
18
|
-
include Breadcrumbing
|
19
|
-
|
20
|
-
def execute
|
21
|
-
breadcrumbs << this
|
22
|
-
data[:foo] = []
|
23
|
-
end
|
24
|
-
|
25
|
-
def post
|
26
|
-
breadcrumbs << this
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class Cmd2
|
31
|
-
include Ccp::Commands::Core
|
32
|
-
include Breadcrumbing
|
33
|
-
|
34
|
-
def pre
|
35
|
-
breadcrumbs << this
|
36
|
-
end
|
37
|
-
|
38
|
-
def execute
|
39
|
-
breadcrumbs << this
|
40
|
-
data[:foo] << "cmd2"
|
41
|
-
end
|
42
|
-
|
43
|
-
def post
|
44
|
-
breadcrumbs << this
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
class Cmd3
|
49
|
-
include Ccp::Commands::Core
|
50
|
-
include Breadcrumbing
|
51
|
-
|
52
|
-
def pre
|
53
|
-
breadcrumbs << this
|
54
|
-
end
|
55
|
-
|
56
|
-
def execute
|
57
|
-
breadcrumbs << this
|
58
|
-
data[:foo] << "cmd3"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class Program
|
63
|
-
include Ccp::Commands::Composite
|
64
|
-
|
65
|
-
command Cmd1
|
66
|
-
command Cmd2
|
67
|
-
command Cmd3
|
68
|
-
end
|
69
|
-
|
70
|
-
subject { Program.new }
|
71
|
-
|
72
|
-
it { should be_kind_of(Ccp::Commands::Core) }
|
73
|
-
|
74
|
-
it "should call sub commands's {pre,execute,post} in declared order" do
|
75
|
-
Breadcrumbing::BREADCRUMBS.clear
|
76
|
-
subject.execute
|
77
|
-
Breadcrumbing::BREADCRUMBS.should ==
|
78
|
-
["Cmd1#execute", "Cmd1#post", "Cmd2#pre", "Cmd2#execute", "Cmd2#post", "Cmd3#pre", "Cmd3#execute"]
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should share same data storage in each sub commands" do
|
82
|
-
subject.execute
|
83
|
-
subject.data[:foo].should == ["cmd2", "cmd3"]
|
84
|
-
end
|
85
|
-
end
|