ccp 0.2.1 → 0.2.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 CHANGED
@@ -157,23 +157,25 @@ This will create following files.
157
157
  % tree tmp/fixtures
158
158
  tmp/fixtures
159
159
  +- tsfc
160
- +- read.json
161
- +- write.json
160
+ +- stub.json
161
+ +- mock.json
162
162
 
163
163
  1 directory, 2 files
164
- % cat tmp/fixtures/tsfc/read.json
164
+ % cat tmp/fixtures/tsfc/stub.json
165
165
  {"a":1}
166
- % cat tmp/fixtures/tsfc/write.json
166
+ % cat tmp/fixtures/tsfc/mock.json
167
167
  {"x":10}
168
168
 
169
+ Where, reading means stub and writing means mock.
170
+
169
171
  === Writing tests
170
172
 
171
173
  Use them as stubs and expected data as you like.
172
174
 
173
175
  describe TSFC do
174
176
  it "should work" do
175
- data = JSON.load(Pathname("tmp/fixtures/tsfc/read.json").read{})
176
- expected = JSON.load(Pathname("tmp/fixtures/tsfc/write.json").read{})
177
+ data = JSON.load(Pathname("tmp/fixtures/tsfc/stub.json").read{})
178
+ expected = JSON.load(Pathname("tmp/fixtures/tsfc/mock.json").read{})
177
179
 
178
180
  cmd = TSFC.execute(data)
179
181
 
@@ -238,8 +240,28 @@ In this case, we want to filter save data. Try fixtures_keys!
238
240
 
239
241
  Cmd.execute(:fixture_save => true, :fixture_keys => ['x'])
240
242
 
241
- This will generate "read.json" that contains only 'x'.
243
+ This will generate "stub.json" that contains only 'x'.
242
244
  And, "!" can be used for negations as same as "Filter commands".
243
245
 
244
246
  Cmd.execute(:fixture_save => true, :fixture_keys => ['!logger'])
245
247
 
248
+ === Static options
249
+
250
+ Static options(hard code) are also available.
251
+
252
+ class Cmd
253
+ include Ccp::Commands::Core
254
+ stub "tmp/stub.json"
255
+ mock "tmp/mock.json"
256
+ # keys ["x"]
257
+ save true
258
+
259
+ def execute
260
+ data[:a]
261
+ data[:x] = 10
262
+ end
263
+ end
264
+
265
+ Cmd.execute(:a=>1)
266
+
267
+ This generates "tmp/stub.json", "tmp/mock.json".
data/ccp.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency "typed", ">= 0.2.2"
22
22
  s.add_dependency "must", ">= 0.2.7"
23
- s.add_dependency "dsl_accessor", ">= 0.4.0"
23
+ s.add_dependency "dsl_accessor", ">= 0.4.1"
24
24
 
25
25
  s.add_development_dependency "rspec"
26
26
  end
data/lib/ccp/commands.rb CHANGED
@@ -4,6 +4,7 @@ module Ccp
4
4
  autoload :Composite , 'ccp/commands/composite'
5
5
  autoload :Executable , 'ccp/commands/executable'
6
6
  autoload :Receivable , 'ccp/commands/receivable'
7
+ autoload :Fixturable , 'ccp/commands/fixturable'
7
8
  autoload :RuntimeArgs , 'ccp/commands/runtime_args'
8
9
  autoload :Commentable , 'ccp/commands/commentable'
9
10
  autoload :Core , 'ccp/commands/core'
@@ -6,6 +6,7 @@ module Ccp
6
6
  base.class_eval do
7
7
  extend ClassMethods
8
8
  extend Executable::ClassMethods
9
+ include Fixturable
9
10
  end
10
11
  end
11
12
 
@@ -6,8 +6,10 @@ module Ccp
6
6
  include Executable
7
7
 
8
8
  def self.included(base)
9
+ super
9
10
  base.class_eval do
10
11
  extend ClassMethods
12
+ include Fixturable
11
13
  end
12
14
  end
13
15
 
@@ -0,0 +1,12 @@
1
+ module Ccp
2
+ module Commands
3
+ module Fixturable
4
+ def self.included(base)
5
+ base.class_eval do
6
+ include Ccp::Utils::Options
7
+ dsl_accessor :fixture, options(:stub, :mock, :fail, :save, :keys, :dir, :kvs, :ext)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/ccp/invokers.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module Ccp
2
2
  module Invokers
3
3
  autoload :Base , 'ccp/invokers/base'
4
+ autoload :Spec , 'ccp/invokers/spec'
4
5
  end
5
6
  end
@@ -4,15 +4,19 @@ module Ccp
4
4
  module Invokers
5
5
  class Base
6
6
  include Commands::Composite
7
+ include Utils::Options
7
8
 
8
9
  dsl_accessor :receiver, Receivers::Base
9
- dsl_accessor :profile , false
10
- dsl_accessor :comment , true
11
- dsl_accessor :logger , proc{ Logger.new($stderr) }
12
10
 
13
- dsl_accessor :builtin_options, :default => {:profile => profile, :comment => comment, :logger => logger}
14
11
  dsl_accessor :default_options, :default => {}
15
12
 
13
+ dsl_accessor :builtins, options(:profile, :comment, :logger)
14
+ dsl_accessor :fixtures, options(:fixture_save, :fixture_keys, :fixture_dir, :fixture_kvs, :fixture_ext)
15
+
16
+ profile false
17
+ comment true
18
+ logger Logger.new($stderr)
19
+
16
20
  ######################################################################
17
21
  ### Class Methods
18
22
 
@@ -23,14 +27,20 @@ module Ccp
23
27
  return cmd
24
28
  end
25
29
 
30
+ def self.receiver_options
31
+ opts = fixtures.options
32
+ opts[:fixture_keys] ||= builtins.options.keys.map{|i| "!#{i}"}
33
+ return opts
34
+ end
35
+
26
36
  ######################################################################
27
37
  ### Instance Methods
28
38
 
29
39
  def initialize(options = {})
30
40
  self.receiver = options.delete(:receiver) || self.class.receiver.new
31
- receiver.parse!(:fixture_keys => self.class.builtin_options.keys.map{|i| "!#{i}"})
41
+ receiver.parse!(self.class.receiver_options)
32
42
  receiver.parse!(options)
33
- receiver.data.default.merge!(self.class.builtin_options)
43
+ receiver.data.default.merge!(self.class.builtins.options)
34
44
  receiver.data.default.merge!(self.class.default_options)
35
45
  end
36
46
 
@@ -0,0 +1,8 @@
1
+ module Ccp
2
+ module Invokers
3
+ class Spec < Base
4
+ def self.spec
5
+ end
6
+ end
7
+ end
8
+ end
@@ -7,6 +7,9 @@ module Ccp::Persistent
7
7
  autoload :Json , 'ccp/persistent/json'
8
8
  autoload :Tsv , 'ccp/persistent/tsv'
9
9
  autoload :Versioned, 'ccp/persistent/versioned'
10
+ autoload :Loadable , 'ccp/persistent/loadable'
11
+
12
+ extend Ccp::Persistent::Loadable
10
13
 
11
14
  def self.lookup(name)
12
15
  case name.to_s
@@ -41,6 +41,16 @@ class Ccp::Persistent::Base
41
41
  raise NotImplementedError, "subclass resposibility"
42
42
  end
43
43
 
44
+ def read
45
+ read!
46
+ rescue Ccp::Persistent::NotFound
47
+ {}
48
+ end
49
+
50
+ def read!
51
+ keys.inject({}) {|h,k| h[k] = v; h}
52
+ end
53
+
44
54
  def keys
45
55
  raise NotImplementedError, "subclass resposibility"
46
56
  end
@@ -11,13 +11,13 @@ class Ccp::Persistent::File < Ccp::Persistent::Base
11
11
  end
12
12
 
13
13
  def exist?(key)
14
- read_data.has_key?(key.to_s)
14
+ read.has_key?(key.to_s)
15
15
  end
16
16
 
17
17
  def load!(key)
18
- hash = read_data
18
+ hash = read
19
19
  if hash.has_key?(key.to_s)
20
- read_data[key.to_s]
20
+ hash[key.to_s]
21
21
  else
22
22
  raise Ccp::Persistent::NotFound, key.to_s
23
23
  end
@@ -30,13 +30,13 @@ class Ccp::Persistent::File < Ccp::Persistent::Base
30
30
  end
31
31
 
32
32
  def []=(key, val)
33
- hash = read_data
33
+ hash = read
34
34
  hash[key.to_s] = val
35
35
  raw_write(encode(hash))
36
36
  end
37
37
 
38
38
  def keys
39
- read_data.keys.sort
39
+ read.keys.sort
40
40
  end
41
41
 
42
42
  def truncate
@@ -47,11 +47,18 @@ class Ccp::Persistent::File < Ccp::Persistent::Base
47
47
  @path ||= Pathname(@source)
48
48
  end
49
49
 
50
- private
51
- def read_data
52
- path.exist? ? decode(path.read{}).must(Hash) : {}
53
- end
50
+ def read
51
+ read!
52
+ rescue Ccp::Persistent::NotFound
53
+ {}
54
+ end
54
55
 
56
+ def read!
57
+ path.exist? or raise Ccp::Persistent::NotFound, path.to_s
58
+ decode(path.read{}).must(Hash)
59
+ end
60
+
61
+ private
55
62
  def raw_write(buf)
56
63
  path.parent.mkpath
57
64
  path.open("w+"){|f| f.print buf}
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Ccp::Persistent::Loadable
4
+ def load(file)
5
+ ext = Ccp::Serializers.lookup(Pathname(file).extname.to_s.delete("."))
6
+ kvs = load_kvs_lookup_by_filename(file)
7
+ kvs.new(file.sub(%r{/$},''), ext)
8
+ end
9
+
10
+ private
11
+ def load_kvs_lookup_by_filename(file)
12
+ case file.to_s
13
+ when %r{/$} ; Ccp::Persistent::Dir
14
+ when %r{\.tsv$}; Ccp::Persistent::Tsv
15
+ else ; Ccp::Persistent::File
16
+ end
17
+ end
18
+ end
@@ -1,31 +1,18 @@
1
1
  module Ccp
2
2
  module Receivers
3
3
  module Fixtures
4
- class Storage
5
- def initialize(kvs)
6
- @kvs = kvs
7
- end
8
-
9
- def save(data)
10
- data.keys.each do |key|
11
- @kvs[key.to_s] = data[key]
12
- end
13
- end
14
-
15
- def load
16
- raise NotImplementedError
17
- end
18
- end
19
-
20
4
  def execute(cmd)
21
- return super unless fixture_save?(cmd)
22
-
23
- observer = Ccp::Fixtures::Observer.new(data)
24
- observer.start
25
- super
26
- observer.stop
27
-
28
- fixture_save(cmd, observer.read, observer.write)
5
+ if fixture_save?(cmd)
6
+ observer = Ccp::Fixtures::Observer.new(data)
7
+ observer.start
8
+ super
9
+ observer.stop
10
+ fixture_save(cmd, observer.read, observer.write)
11
+ else
12
+ fixture_stub(cmd)
13
+ super
14
+ fixture_mock(cmd)
15
+ end
29
16
  end
30
17
 
31
18
  def setup
@@ -52,7 +39,49 @@ module Ccp
52
39
  super
53
40
  end
54
41
 
42
+ def fixture_stub(cmd)
43
+ path = cmd.class.stub or return
44
+ hash = Ccp::Persistent.load(path).read!
45
+ data.merge!(hash)
46
+ end
47
+
48
+ def fixture_mock(cmd)
49
+ path = cmd.class.mock or return
50
+ hash = Ccp::Persistent.load(path).read!
51
+
52
+ hash.keys.each do |key|
53
+ fixture_validate(cmd, key, data, hash)
54
+ end
55
+ end
56
+
57
+ def fixture_validate(cmd, key, data, hash)
58
+ data.exist?(key) or fixture_fail(cmd, key)
59
+ data[key] == hash[key] or fixture_fail(cmd, key, hash[key], data[key])
60
+ # or, success
61
+ end
62
+
63
+ def fixture_fail(cmd, key, expected = nil, got = nil)
64
+ block = fixture_fail_for(cmd)
65
+ instance_exec(cmd, key, expected, got, &block)
66
+ end
67
+
68
+ def fixture_fail_for(cmd)
69
+ cmd.class.fail || method(:default_fixture_fail)
70
+ end
71
+
72
+ def default_fixture_fail(cmd, key, exp, got)
73
+ if exp == nil and got == nil
74
+ raise "#{cmd.class} should write #{key} but not found"
75
+ end
76
+
77
+ exp_info = "%s(%s)" % [exp.inspect.truncate(200), Must::StructInfo.new(exp).compact.inspect]
78
+ got_info = "%s(%s)" % [got.inspect.truncate(200), Must::StructInfo.new(got).compact.inspect]
79
+ raise "%s should create %s for %s, but got %s" % [cmd.class, exp_info, key, got_info]
80
+ end
81
+
55
82
  def fixture_save?(cmd)
83
+ return true if cmd.class.save # highest priority
84
+
56
85
  case (obj = self[:fixture_save])
57
86
  when true ; true
58
87
  when false ; false
@@ -68,19 +97,31 @@ module Ccp
68
97
  end
69
98
  end
70
99
 
71
- def fixture_save(cmd, read, write)
72
- path = self[:fixture_path_for].call(cmd)
73
- versioned = Ccp::Persistent::Versioned.new(path, :kvs=>self[:fixture_kvs], :ext=>self[:fixture_ext])
74
- versioned["read" ].save(read , fixture_keys_filter(read.keys))
75
- versioned["write"].save(write, fixture_keys_filter(write.keys))
100
+ def fixture_save(cmd, stub, mock)
101
+ path = self[:fixture_path_for].call(cmd)
102
+ path = Pathname(cmd.class.dir) + cmd.class.name.underscore if cmd.class.dir
103
+
104
+ keys = cmd.class.keys || self[:fixture_keys]
105
+ kvs = cmd.class.kvs || self[:fixture_kvs]
106
+ ext = cmd.class.ext || self[:fixture_ext]
107
+
108
+ versioned = Ccp::Persistent::Versioned.new(path, :kvs=>kvs, :ext=>ext)
109
+
110
+ # stub
111
+ storage = cmd.class.stub ? Ccp::Persistent.lookup(kvs).new(cmd.class.stub, ext) : versioned["stub"]
112
+ storage.save(stub, fixture_keys_filter(keys, stub.keys))
113
+
114
+ # mock
115
+ storage = cmd.class.mock ? Ccp::Persistent.lookup(kvs).new(cmd.class.mock, ext) : versioned["mock"]
116
+ storage.save(mock, fixture_keys_filter(keys, mock.keys))
76
117
  end
77
118
 
78
- def fixture_keys_filter(keys)
79
- case (obj = self[:fixture_keys])
119
+ def fixture_keys_filter(acl, keys)
120
+ case acl
80
121
  when true ; keys
81
122
  when false; []
82
123
  when Array
83
- ary = obj.map(&:to_s)
124
+ ary = acl.map(&:to_s)
84
125
  return keys if ary == []
85
126
  if ary.size == ary.grep(/^!/).size
86
127
  return keys.dup.reject{|v| ary.include?("!#{v}")}
@@ -88,17 +129,10 @@ module Ccp
88
129
  ary & keys
89
130
  end
90
131
  else
91
- raise ":fixture_keys is invalid: #{obj.class}"
132
+ raise ":fixture_keys is invalid: #{acl.class}"
92
133
  end
93
134
  end
94
135
 
95
- def fixture_for(cmd, key)
96
- kvs = Ccp::Persistent.lookup(self[:fixture_kvs])
97
- code = Ccp::Serializers.lookup(self[:fixture_ext])
98
- path = instance_exec(cmd, &self[:fixture_path_for]) + "#{key}.#{code.ext}.#{kvs.ext}"
99
- return Storage.new(kvs.new(path, code))
100
- end
101
-
102
136
  def default_fixture_path_for
103
137
  proc{|cmd| settings.path(:fixture_dir) + cmd.class.name.underscore}
104
138
  end
data/lib/ccp/utils.rb CHANGED
@@ -2,5 +2,6 @@ module Ccp
2
2
  module Utils
3
3
  autoload :Data , 'ccp/utils/data'
4
4
  autoload :Colorize , 'ccp/utils/colorize'
5
+ autoload :Options , 'ccp/utils/options'
5
6
  end
6
7
  end
@@ -0,0 +1,6 @@
1
+ module Ccp
2
+ module Utils
3
+ class FixtureOptions < Options::Proxy
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,50 @@
1
+ module Ccp
2
+ module Utils
3
+ module Options
4
+ def self.included(base)
5
+ super
6
+
7
+ class << base
8
+ def options(*keys)
9
+ Proxy.new(self, *keys)
10
+ end
11
+ end
12
+ end
13
+
14
+ class Proxy
15
+ include Enumerable
16
+
17
+ attr_reader :keys
18
+
19
+ def initialize(base, *keys)
20
+ @base = base
21
+ @keys = keys.map(&:to_sym)
22
+
23
+ @keys.each do |key|
24
+ @base.dsl_accessor key
25
+ # instance_eval "def self.#{key}; :#{key}; end"
26
+ end
27
+ end
28
+
29
+ def [](key)
30
+ @base.__send__(key)
31
+ end
32
+
33
+ def each(&block)
34
+ keys.each do |key|
35
+ yield(self[key])
36
+ end
37
+ end
38
+
39
+ def options
40
+ opts = {}
41
+ keys.each do |key|
42
+ val = self[key]
43
+ opts[key] = val unless val.nil?
44
+ end
45
+ return opts
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
data/lib/ccp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ccp
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -1,5 +1,23 @@
1
1
  require "spec_helper"
2
2
 
3
+ describe Ccp::Commands::Composite do
4
+ describe "(instance)" do
5
+ subject { Object.new.extend Ccp::Commands::Composite }
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
+
15
+ # receivable
16
+ it { should respond_to(:receiver) }
17
+ its(:receiver) { should be_kind_of(Ccp::Receivers::Base) }
18
+ end
19
+ end
20
+
3
21
  describe Ccp::Commands::Composite do
4
22
  describe "#execute" do
5
23
  it "should call its execute and sub commands's {before,execute,after} in declared order" do
@@ -0,0 +1,66 @@
1
+ require "spec_helper"
2
+
3
+ describe Ccp::Commands::Core do
4
+ subject { Class.new{include Ccp::Commands::Core} }
5
+
6
+ it { should include(Ccp::Commands::Fixturable) }
7
+ end
8
+
9
+ describe Ccp::Commands::Fixturable do
10
+ context "Ccp::Commands::Core" do
11
+ subject { Cmd1 }
12
+ it { should respond_to("stub") }
13
+ it { should respond_to("mock") }
14
+ it { should respond_to("fail") }
15
+ it { should respond_to("save") }
16
+ it { should respond_to("keys") }
17
+ it { should respond_to("dir") }
18
+ it { should respond_to("kvs") }
19
+ it { should respond_to("ext") }
20
+ it { should respond_to("fixture") }
21
+ its(:fixture) { should respond_to("options") }
22
+ end
23
+
24
+ context "Ccp::Commands::Composite" do
25
+ subject { Program }
26
+ it { should respond_to("stub") }
27
+ it { should respond_to("mock") }
28
+ it { should respond_to("fail") }
29
+ it { should respond_to("save") }
30
+ it { should respond_to("keys") }
31
+ it { should respond_to("dir") }
32
+ it { should respond_to("kvs") }
33
+ it { should respond_to("ext") }
34
+ it { should respond_to("fixture") }
35
+ its(:fixture) { should respond_to("options") }
36
+ end
37
+
38
+ context "Ccp::Invokers::Base" do
39
+ subject { CompositeInvoker }
40
+ it { should respond_to("stub") }
41
+ it { should respond_to("mock") }
42
+ it { should respond_to("fail") }
43
+ it { should respond_to("save") }
44
+ it { should respond_to("keys") }
45
+ it { should respond_to("dir") }
46
+ it { should respond_to("kvs") }
47
+ it { should respond_to("ext") }
48
+ it { should respond_to("fixture") }
49
+ its(:fixture) { should respond_to("options") }
50
+ end
51
+
52
+ context "included class" do
53
+ subject { Class.new{include Ccp::Commands::Fixturable} }
54
+ it { should respond_to("stub") }
55
+ it { should respond_to("mock") }
56
+ it { should respond_to("fail") }
57
+ it { should respond_to("save") }
58
+ it { should respond_to("keys") }
59
+ it { should respond_to("dir") }
60
+ it { should respond_to("kvs") }
61
+ it { should respond_to("ext") }
62
+ it { should respond_to("fixture") }
63
+ its(:fixture) { should respond_to("options") }
64
+ end
65
+ end
66
+
@@ -0,0 +1 @@
1
+ {"breadcrumbs":["Cmd1StubMock#before", "Cmd1StubMock#execute", "Cmd1StubMock#after"]}
@@ -0,0 +1 @@
1
+ {"breadcrumbs":[]}
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+ require 'fileutils'
3
+
4
+ describe Ccp::Invokers::Base do
5
+ describe "(class)" do
6
+ subject {Class.new(Ccp::Invokers::Base)}
7
+ it { should respond_to(:fixture_save) }
8
+ it { should respond_to(:fixture_keys) }
9
+ it { should respond_to(:fixture_dir) }
10
+ it { should respond_to(:fixture_kvs) }
11
+ it { should respond_to(:fixture_ext) }
12
+ end
13
+ end
@@ -2,29 +2,21 @@ require "spec_helper"
2
2
  require 'fileutils'
3
3
 
4
4
  describe Ccp::Invokers::Base do
5
- def load(path)
6
- case path.extname
7
- when ".json"; JSON.load(Pathname(path).read{})
8
- when ".yaml"; YAML.load(Pathname(path).read{})
9
- else; raise "load doesn't support #{path.extname}"
10
- end
11
- end
12
-
13
5
  describe ".execute" do
14
6
  before do
15
7
  FileUtils.rm_rf("tmp")
16
8
  end
17
9
 
18
10
  context "(:fixture_save=>true)" do
19
- it "should generate read/write fixtures in tmp/fixtures as json files" do
11
+ it "should generate stub/mock fixtures in tmp/fixtures as json files" do
20
12
  path = Pathname("tmp/fixtures")
21
13
  data = {:breadcrumbs => []}
22
14
  opts = {:fixture_save=>true}
23
15
 
24
16
  CompositeInvoker.execute(data.merge(opts))
25
17
 
26
- (read = path + "composite_invoker/read.json" ).should exist
27
- load(read)["breadcrumbs"].should ==
18
+ (stub = path + "composite_invoker/stub.json" ).should exist
19
+ load_fixture(stub)["breadcrumbs"].should ==
28
20
  ["CompositeInvoker#before",
29
21
  "Cmd1#before", "Cmd1#execute", "Cmd1#after",
30
22
  "Cmd23#before",
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+ require 'fileutils'
3
+
4
+ describe Ccp::Invokers::Spec do
5
+ it "should inherit Ccp::Invokers::Base" do
6
+ subject.should be_kind_of(Ccp::Invokers::Base)
7
+ end
8
+
9
+ describe "(class)" do
10
+ subject { Ccp::Invokers::Spec }
11
+ it { should respond_to("spec") }
12
+ end
13
+ end
14
+
15
+
16
+ __END__
17
+
18
+ class Cmd1Spec < Ccp::Invokers::Spec
19
+ fixture_dir "spec/fixtures/invokers/spec/stub"
20
+ command Cmd1
21
+ end
22
+
23
+ it "should stub data" do
24
+ path = truncate_pathname("tmp/fixtures/spec/invokers/spec/stub")
25
+ save_fixture(path + "stub.json", "breadcrumbs"=>[])
26
+
27
+ lambda {
28
+ Cmd1Spec.execute
29
+ }.should raise_error(Typed::NotDefined)
30
+
31
+ lambda {
32
+ Cmd1Spec.spec
33
+ }.should_not raise_error
34
+ end
35
+ end
36
+
@@ -11,39 +11,15 @@ describe Ccp::Persistent::Base do
11
11
  end
12
12
  end
13
13
 
14
- it "should provide ext" do
15
- subject.methods.include?("ext").should == true
16
- end
17
-
18
- it "should provide exist?" do
19
- subject.methods.include?("exist?").should == true
20
- end
21
-
22
- it "should provide #save" do
23
- subject.methods.include?("save").should == true
24
- end
25
-
26
- it "should provide #load!" do
27
- subject.methods.include?("load!").should == true
28
- end
29
-
30
- it "should provide #load" do
31
- subject.methods.include?("load").should == true
32
- end
33
-
34
- it "should provide #[]" do
35
- subject.methods.include?("[]").should == true
36
- end
37
-
38
- it "should provide #[]=" do
39
- subject.methods.include?("[]=").should == true
40
- end
41
-
42
- it "should provide #keys" do
43
- subject.methods.include?("keys").should == true
44
- end
45
-
46
- it "should provide #truncate" do
47
- subject.methods.include?("truncate").should == true
48
- end
14
+ it { should respond_to("ext") }
15
+ it { should respond_to("exist?") }
16
+ it { should respond_to("save") }
17
+ it { should respond_to("load!") }
18
+ it { should respond_to("load") }
19
+ it { should respond_to("[]") }
20
+ it { should respond_to("[]=") }
21
+ it { should respond_to("read") }
22
+ it { should respond_to("read!") }
23
+ it { should respond_to("keys") }
24
+ it { should respond_to("truncate") }
49
25
  end
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require 'fileutils'
4
+
5
+ describe Ccp::Persistent do
6
+ it { should respond_to("load") }
7
+
8
+ describe ".load" do
9
+ context "('tmp/foo.json')" do
10
+ subject { Ccp::Persistent.load('tmp/foo.json') }
11
+ its(:class) { should == Ccp::Persistent::File }
12
+ its(:ext) { should == "json" }
13
+ its(:source) { should == 'tmp/foo.json' }
14
+ end
15
+
16
+ context "('tmp/foo.yaml')" do
17
+ subject { Ccp::Persistent.load('tmp/foo.yaml') }
18
+ its(:class) { should == Ccp::Persistent::File }
19
+ its(:ext) { should == "yaml" }
20
+ its(:source) { should == 'tmp/foo.yaml' }
21
+ end
22
+
23
+ context "('tmp/foo.json/')" do
24
+ subject { Ccp::Persistent.load('tmp/foo.json/') }
25
+ its(:class) { should == Ccp::Persistent::Dir }
26
+ its(:ext) { should == "json" }
27
+ its(:source) { should == 'tmp/foo.json' }
28
+ end
29
+
30
+ context "('tmp/foo')" do
31
+ it "should raise Ccp::Serializers::NotFound" do
32
+ lambda {
33
+ Ccp::Persistent.load('tmp/foo')
34
+ }.should raise_error(Ccp::Serializers::NotFound)
35
+ end
36
+ end
37
+
38
+ context "('tmp/foo/')" do
39
+ it "should raise Ccp::Serializers::NotFound" do
40
+ lambda {
41
+ Ccp::Persistent.load('tmp/foo/')
42
+ }.should raise_error(Ccp::Serializers::NotFound)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -8,41 +8,41 @@ describe "Ccp::Commands::Core" do
8
8
  end
9
9
 
10
10
  context "(:fixture_save=>true)" do
11
- it "should generate read/write fixtures in tmp/fixtures as json files" do
11
+ it "should generate stub/mock fixtures in tmp/fixtures as json files" do
12
12
  path = Pathname("tmp/fixtures")
13
13
  data = {:a=>"a", :b=>"b", :x=>1, :y=>2}
14
14
  opts = {:fixture_save=>true}
15
15
 
16
16
  TSFC.execute(data.merge(opts))
17
17
 
18
- load_fixture(path + "tsfc/read.json" ).should == {"a" => "a"}
19
- load_fixture(path + "tsfc/write.json").should == {"x" => 10}
18
+ load_fixture(path + "tsfc/stub.json").should == {"a" => "a"}
19
+ load_fixture(path + "tsfc/mock.json").should == {"x" => 10}
20
20
  end
21
21
  end
22
22
 
23
23
  context "(:fixture_save=>true, :fixture_ext=>:yaml)" do
24
- it "should generate read/write fixtures in tmp/fixtures as yaml files" do
24
+ it "should generate stub/mock fixtures in tmp/fixtures as yaml files" do
25
25
  path = Pathname("tmp/fixtures")
26
26
  data = {:a=>"a", :b=>"b", :x=>1, :y=>2}
27
27
  opts = {:fixture_save=>true, :fixture_ext=>:yaml}
28
28
 
29
29
  TSFC.execute(data.merge(opts))
30
30
 
31
- load_fixture(path + "tsfc/read.yaml" ).should == {"a" => "a"}
32
- load_fixture(path + "tsfc/write.yaml").should == {"x" => 10}
31
+ load_fixture(path + "tsfc/stub.yaml" ).should == {"a" => "a"}
32
+ load_fixture(path + "tsfc/mock.yaml").should == {"x" => 10}
33
33
  end
34
34
  end
35
35
 
36
36
  context "(:fixture_save=>true, :fixture_kvs=>:dir)" do
37
- it "should generate json files in read/write dir" do
37
+ it "should generate json files in stub/mock dir" do
38
38
  path = Pathname("tmp/fixtures")
39
39
  data = {:a=>"a", :b=>"b", :x=>1, :y=>2}
40
40
  opts = {:fixture_save=>true, :fixture_kvs=>:dir}
41
41
 
42
42
  TSFC.execute(data.merge(opts))
43
43
 
44
- load_fixture(path + "tsfc/read.json/a.json" ).should == "a"
45
- load_fixture(path + "tsfc/write.json/x.json").should == 10
44
+ load_fixture(path + "tsfc/stub.json/a.json" ).should == "a"
45
+ load_fixture(path + "tsfc/mock.json/x.json").should == 10
46
46
  end
47
47
  end
48
48
  end
@@ -21,8 +21,8 @@ describe Ccp::Invokers::Base do
21
21
  it "should ignore :logger in default" do
22
22
  ULI.execute(:a=>"a", :fixture_save=>true)
23
23
 
24
- load_fixture("tmp/fixtures/uli/read.json" ).should == {"a" => "a"}
25
- load_fixture("tmp/fixtures/uli/write.json" ).should == {"x" => 10}
24
+ load_fixture("tmp/fixtures/uli/stub.json").should == {"a" => "a"}
25
+ load_fixture("tmp/fixtures/uli/mock.json").should == {"x" => 10}
26
26
  end
27
27
  end
28
28
  end
@@ -13,7 +13,7 @@ describe Cmd1 do
13
13
  end
14
14
 
15
15
  def created_keys
16
- load_fixture(FIXTURE_PATH + "read.json").keys.sort
16
+ load_fixture(FIXTURE_PATH + "stub.json").keys.sort
17
17
  rescue Errno::ENOENT
18
18
  []
19
19
  end
@@ -8,15 +8,51 @@ describe "Ccp::Commands::Core" do
8
8
  end
9
9
 
10
10
  context "(:fixture_save=>true, :fixture_dir=>...)" do
11
- it "should generate read/write fixtures in <save_fixture_dir> as json files" do
11
+ it "should generate stub/mock fixtures in <save_fixture_dir> as json files" do
12
12
  path = Pathname("tmp/test/fixtures")
13
13
  data = {:a=>"a", :b=>"b", :x=>1, :y=>2}
14
14
  opts = {:fixture_save=>true, :fixture_dir=>path.to_s}
15
15
 
16
16
  TSFC.execute(data.merge(opts))
17
17
 
18
- load_fixture(path + "tsfc/read.json" ).should == {"a" => "a"}
19
- load_fixture(path + "tsfc/write.json").should == {"x" => 10}
18
+ load_fixture(path + "tsfc/stub.json").should == {"a" => "a"}
19
+ load_fixture(path + "tsfc/mock.json").should == {"x" => 10}
20
+ end
21
+ end
22
+
23
+ context "(:fixture_save=>true) with hard coded" do
24
+ it "should generate fixtures in given path" do
25
+ data = {:a=>"a", :b=>"b", :x=>1, :y=>2}
26
+ opts = {:fixture_save=>true}
27
+
28
+ begin
29
+ TSFC.stub "tmp/tsfc/in.json"
30
+ TSFC.mock "tmp/tsfc/out.json"
31
+
32
+ TSFC.execute(data.merge(opts))
33
+ ensure
34
+ TSFC.stub nil
35
+ TSFC.mock nil
36
+ end
37
+
38
+ load_fixture("tmp/tsfc/in.json").should == {"a" => "a"}
39
+ load_fixture("tmp/tsfc/out.json").should == {"x" => 10}
40
+ end
41
+
42
+ it "should generate stub/mock fixtures in <dir> as json files" do
43
+ data = {:a=>"a", :b=>"b", :x=>1, :y=>2}
44
+ opts = {:fixture_save=>true}
45
+
46
+ begin
47
+ TSFC.dir "tmp/foo"
48
+
49
+ TSFC.execute(data.merge(opts))
50
+ ensure
51
+ TSFC.dir nil
52
+ end
53
+
54
+ load_fixture("tmp/foo/tsfc/stub.json").should == {"a" => "a"}
55
+ load_fixture("tmp/foo/tsfc/mock.json").should == {"x" => 10}
20
56
  end
21
57
  end
22
58
  end
@@ -13,7 +13,7 @@ describe Ccp::Commands::Composite do
13
13
  end
14
14
 
15
15
  def created_fixtures
16
- Dir.chdir(FIXTURE_ROOT){Dir["*/read.json"].map{|i| File.dirname(i)}.sort}
16
+ Dir.chdir(FIXTURE_ROOT){Dir["*/stub.json"].map{|i| File.dirname(i)}.sort}
17
17
  rescue Errno::ENOENT
18
18
  []
19
19
  end
@@ -88,5 +88,27 @@ describe Ccp::Commands::Composite do
88
88
  execute(:fixture_save => ['Cmd1','!Cmd1']) do
89
89
  ['cmd1']
90
90
  end
91
+
92
+ ######################################################################
93
+ ### hard coded
94
+ context "(hard coded)" do
95
+ before { Cmd2.save true }
96
+ after { Cmd2.save false }
97
+
98
+ # will save if hard coded is enabled
99
+ execute do
100
+ ['cmd2']
101
+ end
102
+
103
+ # respect hard coded even if runtime args are given
104
+ execute(:fixture_save => ['Cmd1']) do
105
+ ['cmd1', 'cmd2']
106
+ end
107
+
108
+ # respect it even if it is rejected by runtime args
109
+ execute(:fixture_save => ['!Cmd1', '!Cmd2']) do
110
+ ["cmd2", "cmd3", "program"]
111
+ end
112
+ end
91
113
  end
92
114
  end
@@ -0,0 +1,64 @@
1
+ require "spec_helper"
2
+
3
+ describe Ccp::Receivers::Fixtures do
4
+ context "(stub)" do
5
+ class Cmd1Stub < Cmd1
6
+ stub "spec/fixtures/stub/breadcrumbs.json"
7
+ end
8
+
9
+ it "should merge given data file into data variable" do
10
+ lambda {
11
+ Cmd1.execute
12
+ }.should raise_error(Typed::NotDefined)
13
+
14
+ lambda {
15
+ Cmd1Stub.execute
16
+ }.should_not raise_error
17
+ end
18
+ end
19
+
20
+ context "(stub and mock)" do
21
+ class Cmd1StubMock < Cmd1
22
+ stub "spec/fixtures/stub/breadcrumbs.json"
23
+ mock "spec/fixtures/cmd1stub_mock/mock.json"
24
+ end
25
+
26
+ it "should raise when current data doesn't match the given data" do
27
+ lambda {
28
+ Cmd1StubMock.execute
29
+ }.should_not raise_error
30
+ end
31
+ end
32
+
33
+ context "(stub and invalid mock)" do
34
+ class Cmd1StubInvalidMock < Cmd1
35
+ stub "spec/fixtures/stub/breadcrumbs.json"
36
+ mock "spec/fixtures/stub/breadcrumbs.json"
37
+ end
38
+
39
+ it "should raise when current data doesn't match the given data" do
40
+ lambda {
41
+ Cmd1StubInvalidMock.execute
42
+ }.should raise_error(/should create/)
43
+ end
44
+ end
45
+
46
+ context "(stub and mock and fail)" do
47
+ class Cmd1StubInvalidMockWithFail < Cmd1
48
+ dsl_accessor :failed, false
49
+
50
+ stub "spec/fixtures/stub/breadcrumbs.json"
51
+ mock "spec/fixtures/stub/breadcrumbs.json"
52
+
53
+ fail do |cmd, key, expected, got|
54
+ Cmd1StubInvalidMockWithFail.failed true
55
+ end
56
+ end
57
+
58
+ it "should raise when current data doesn't match the given data" do
59
+ Cmd1StubInvalidMockWithFail.failed.should == false
60
+ Cmd1StubInvalidMockWithFail.execute
61
+ Cmd1StubInvalidMockWithFail.failed.should == true
62
+ end
63
+ end
64
+ end
@@ -5,15 +5,7 @@ require 'fileutils'
5
5
  describe Ccp::Serializers::Core do
6
6
  subject { Object.new.extend Ccp::Serializers::Core }
7
7
 
8
- it "should provide ext" do
9
- subject.methods.include?("ext").should == true
10
- end
11
-
12
- it "should provide encode" do
13
- subject.methods.include?("encode").should == true
14
- end
15
-
16
- it "should provide decode" do
17
- subject.methods.include?("decode").should == true
18
- end
8
+ it { should respond_to("ext") }
9
+ it { should respond_to("encode") }
10
+ it { should respond_to("decode") }
19
11
  end
data/spec/spec_helper.rb CHANGED
@@ -12,11 +12,24 @@ def breadcrumbs_receiver
12
12
  return r
13
13
  end
14
14
 
15
+ def lookup_serializer(extname)
16
+ {".json"=>JSON, ".yaml"=>YAML}[extname] or raise "no serializers for #{extname}"
17
+ end
18
+
15
19
  def load_fixture(path)
16
20
  path = Pathname(path)
17
- case path.extname
18
- when ".json"; JSON.load(Pathname(path).read{})
19
- when ".yaml"; YAML.load(Pathname(path).read{})
20
- else; raise "load doesn't support #{path.extname}"
21
- end
21
+ lookup_serializer(path.extname).load(path.read{})
22
+ end
23
+
24
+ def save_fixture(path, obj)
25
+ path = Pathname(path)
26
+ buf = lookup_serializer(path.extname).dump(obj)
27
+ path.open("w+"){|f| f.print buf}
28
+ end
29
+
30
+ def truncate_pathname(dir)
31
+ path = Pathname(dir)
32
+ FileUtils.rm_rf(path.to_s)
33
+ path.mkpath
34
+ return path
22
35
  end
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: 21
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
9
+ - 3
10
+ version: 0.2.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-05-07 00:00:00 +09:00
18
+ date: 2012-05-10 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -58,12 +58,12 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- hash: 15
61
+ hash: 13
62
62
  segments:
63
63
  - 0
64
64
  - 4
65
- - 0
66
- version: 0.4.0
65
+ - 1
66
+ version: 0.4.1
67
67
  type: :runtime
68
68
  version_requirements: *id003
69
69
  - !ruby/object:Gem::Dependency
@@ -103,6 +103,7 @@ files:
103
103
  - lib/ccp/commands/composite.rb
104
104
  - lib/ccp/commands/core.rb
105
105
  - lib/ccp/commands/executable.rb
106
+ - lib/ccp/commands/fixturable.rb
106
107
  - lib/ccp/commands/receivable.rb
107
108
  - lib/ccp/commands/resolvable.rb
108
109
  - lib/ccp/fixtures.rb
@@ -110,10 +111,12 @@ files:
110
111
  - lib/ccp/fixtures/writers.rb
111
112
  - lib/ccp/invokers.rb
112
113
  - lib/ccp/invokers/base.rb
114
+ - lib/ccp/invokers/spec.rb
113
115
  - lib/ccp/persistent.rb
114
116
  - lib/ccp/persistent/base.rb
115
117
  - lib/ccp/persistent/dir.rb
116
118
  - lib/ccp/persistent/file.rb
119
+ - lib/ccp/persistent/loadable.rb
117
120
  - lib/ccp/persistent/tsv.rb
118
121
  - lib/ccp/persistent/versioned.rb
119
122
  - lib/ccp/receivers.rb
@@ -134,17 +137,25 @@ files:
134
137
  - lib/ccp/serializers/yaml.rb
135
138
  - lib/ccp/utils.rb
136
139
  - lib/ccp/utils/colorize.rb
140
+ - lib/ccp/utils/fixture_options.rb
141
+ - lib/ccp/utils/options.rb
137
142
  - lib/ccp/version.rb
138
143
  - spec/commands/base_spec.rb
139
144
  - spec/commands/composite_spec.rb
140
145
  - spec/commands/core_spec.rb
141
146
  - spec/commands/executable_spec.rb
147
+ - spec/commands/fixturable_spec.rb
148
+ - spec/fixtures/cmd1stub_mock/mock.json
149
+ - spec/fixtures/stub/breadcrumbs.json
142
150
  - spec/invokers/base_spec.rb
151
+ - spec/invokers/fixture_spec.rb
143
152
  - spec/invokers/save_fixture_spec.rb
153
+ - spec/invokers/spec_spec.rb
144
154
  - spec/models.rb
145
155
  - spec/persistent/base_spec.rb
146
156
  - spec/persistent/dir_spec.rb
147
157
  - spec/persistent/file_spec.rb
158
+ - spec/persistent/loadable_spec.rb
148
159
  - spec/persistent/tsv_spec.rb
149
160
  - spec/persistent/versioned_spec.rb
150
161
  - spec/receivers/fixture_save_how_spec.rb
@@ -152,6 +163,7 @@ files:
152
163
  - spec/receivers/fixture_save_what_spec.rb
153
164
  - spec/receivers/fixture_save_where_spec.rb
154
165
  - spec/receivers/fixture_save_why_spec.rb
166
+ - spec/receivers/fixture_stub_spec.rb
155
167
  - spec/serializers/core_spec.rb
156
168
  - spec/serializers/json_spec.rb
157
169
  - spec/serializers/spec.rb