code_driven_development 0.0.3 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b09b6d5336aaa29537662229c0c204572ee2e81d
4
- data.tar.gz: 610a995a3c9012fbd5d6ff374b096793e6fbf259
3
+ metadata.gz: 546316dbe66b0a333a9dd89b55222bacd74e502b
4
+ data.tar.gz: 07c3576f12dc0b9667ed79145994e55c5dc344d3
5
5
  SHA512:
6
- metadata.gz: e83e416be1af608df38ae343b34e7c10dc6775a98f8b3290348eeb4bc4634a83c39beb0aaca10498697ba8761ef89672ff7985f021ee5ee6754b5522af94884d
7
- data.tar.gz: 900dd1f8ce764b77eec4126e39d66d5c5d2028696bd24a3cb7d6d7ef749f9d631408639bd0c30bb672413c481c724506398264343bbb7f43907f49bade1c3076
6
+ metadata.gz: 01bc5e3a0b27dcc595473b5bb8312f538c785c1e33efa341e12b7c85f25514ff83e11eded00b194031f6006298f3df764e8b2b316c59542db03e6b9f154af936
7
+ data.tar.gz: a023a61a8c1ecd86ae3c5e5e353902b53ce51da33e98af64ca36c759d993d9e2c1baddd6b366e3c8e6123aa1875fe7aeb48c3db98db47ccf6c1cb6ec4fe5029f
data/README.md CHANGED
@@ -13,9 +13,8 @@ class Bunker < ActiveRecord::Base
13
13
  end
14
14
 
15
15
  def alert_president
16
- alert_staff
17
16
  SecretService.stand_down
18
- President.alert
17
+ alert_staff || go_crazy
19
18
  end
20
19
  end
21
20
  ```
@@ -23,38 +22,55 @@ end
23
22
  And this is what CDD thinks of it:
24
23
 
25
24
  ``` ruby
26
-
27
25
  describe Bunker do
28
26
  it { should validate_secure_of :password }
29
27
  it { should validate_protected_of :location }
30
-
31
28
  describe "#alert_staff" do
32
29
  let(:obj) { described_class.new }
30
+ subject { obj.alert_staff }
33
31
  before do
34
32
  allow(Staff).to receive :alert_all
35
- obj.alert_staff
36
33
  end
37
34
  it "calls Staff.alert_all" do
35
+ subject
38
36
  expect(Staff).to have_received :alert_all
39
37
  end
40
38
  end
41
-
42
39
  describe "#alert_president" do
43
40
  let(:obj) { described_class.new }
41
+ subject { obj.alert_president }
44
42
  before do
45
- allow(obj).to receive :alert_staff
46
43
  allow(SecretService).to receive :stand_down
47
- allow(President).to receive :alert
48
- obj.alert_president
49
- end
50
- it "calls #alert_staff" do
51
- expect(obj).to have_received :alert_staff
52
44
  end
53
45
  it "calls SecretService.stand_down" do
46
+ subject
54
47
  expect(SecretService).to have_received :stand_down
55
48
  end
56
- it "calls President.alert" do
57
- expect(President).to have_received :alert
49
+ describe "#alert_staff is truthy" do
50
+ before do
51
+ allow(obj).to receive(:alert_staff).and_return('alert_staff')
52
+ allow(obj).to receive(:go_crazy)
53
+ end
54
+ it "returns #alert_staff" do
55
+ expect(subject).to eq 'alert_staff'
56
+ end
57
+ it "doesn't call #go_crazy" do
58
+ subject
59
+ expect(obj).not_to have_received :go_crazy
60
+ end
61
+ end
62
+ describe "#alert_staff is falsey" do
63
+ before do
64
+ allow(obj).to receive(:alert_staff).and_return(false)
65
+ allow(obj).to receive(:go_crazy).and_return('go_crazy')
66
+ end
67
+ it "returns #go_crazy" do
68
+ expect(subject).to eq 'go_crazy'
69
+ end
70
+ it "calls #alert_staff" do
71
+ subject
72
+ expect(obj).to have_received :alert_staff
73
+ end
58
74
  end
59
75
  end
60
76
  end
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../../lib')
2
+
1
3
  require "bundler/gem_tasks"
4
+ require 'cucumber/rake/task'
5
+
6
+ Cucumber::Rake::Task.new
7
+
8
+ task default: :cucumber
@@ -24,4 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "rspec"
26
26
  spec.add_development_dependency "pry"
27
+ spec.add_development_dependency "cucumber"
28
+ spec.add_development_dependency "aruba"
27
29
  end
@@ -0,0 +1,113 @@
1
+ Feature: Creates awesome specs
2
+ Scenario: creating shoulda_matchers
3
+ Given a file named "my_feature.rb" with:
4
+ """ruby
5
+ class Lolcat < ActiveRecord::Base
6
+ validate :cuteness, presence: true
7
+ end
8
+ """
9
+ When I run `cdd my_feature.rb`
10
+ Then the exit status should be 0
11
+ And the output should contain:
12
+ """ruby
13
+ describe Lolcat do
14
+ it { should validate_presence_of :cuteness }
15
+ end
16
+ """
17
+
18
+ Scenario: instance methods that call constants
19
+ Given a file named "my_feature.rb" with:
20
+ """ruby
21
+ class Lolcat
22
+ def i_call_things
23
+ CentralBureaucracy.file_report
24
+ end
25
+ end
26
+ """
27
+ When I run `cdd my_feature.rb`
28
+ Then the exit status should be 0
29
+ And the output should contain:
30
+ """ruby
31
+ describe "#i_call_things" do
32
+ let(:obj) { described_class.new }
33
+ subject { obj.i_call_things }
34
+ before do
35
+ allow(CentralBureaucracy).to receive :file_report
36
+ end
37
+ it "calls CentralBureaucracy.file_report" do
38
+ subject
39
+ expect(CentralBureaucracy).to have_received :file_report
40
+ end
41
+ end
42
+ """
43
+
44
+ Scenario: instance methods that call instance methods
45
+ Given a file named "my_feature.rb" with:
46
+ """ruby
47
+ class Lolcat
48
+ def i_call_instance_methods
49
+ meth
50
+ end
51
+ end
52
+ """
53
+ When I run `cdd my_feature.rb`
54
+ Then the exit status should be 0
55
+ And the output should contain:
56
+ """ruby
57
+ describe "#i_call_instance_methods" do
58
+ let(:obj) { described_class.new }
59
+ subject { obj.i_call_instance_methods }
60
+ before do
61
+ allow(obj).to receive :meth
62
+ end
63
+ it "calls #meth" do
64
+ subject
65
+ expect(obj).to have_received :meth
66
+ end
67
+ end
68
+ """
69
+
70
+ Scenario: boolean or
71
+ Given a file named "my_feature.rb" with:
72
+ """ruby
73
+ class Yolounicorn
74
+ def dilemma
75
+ should_i_stay || should_i_go
76
+ end
77
+ end
78
+ """
79
+ When I run `cdd my_feature.rb`
80
+ Then the exit status should be 0
81
+ And the output should contain:
82
+ """ruby
83
+ describe "#dilemma" do
84
+ let(:obj) { described_class.new }
85
+ subject { obj.dilemma }
86
+ describe "#should_i_stay is truthy" do
87
+ before do
88
+ allow(obj).to receive(:should_i_stay).and_return('should_i_stay')
89
+ allow(obj).to receive(:should_i_go)
90
+ end
91
+ it "returns #should_i_stay" do
92
+ expect(subject).to eq 'should_i_stay'
93
+ end
94
+ it "doesn't call #should_i_go" do
95
+ subject
96
+ expect(obj).not_to have_received :should_i_go
97
+ end
98
+ end
99
+ describe "#should_i_stay is falsey" do
100
+ before do
101
+ allow(obj).to receive(:should_i_stay).and_return(false)
102
+ allow(obj).to receive(:should_i_go).and_return('should_i_go')
103
+ end
104
+ it "returns #should_i_go" do
105
+ expect(subject).to eq 'should_i_go'
106
+ end
107
+ it "calls #should_i_stay" do
108
+ subject
109
+ expect(obj).to have_received :should_i_stay
110
+ end
111
+ end
112
+ end
113
+ """
@@ -0,0 +1 @@
1
+ require 'aruba/cucumber'
@@ -25,6 +25,7 @@ module CodeDrivenDevelopment
25
25
  Rule::InstanceMethod,
26
26
  Rule::ConstantMethodCall,
27
27
  Rule::InstanceMethodCall,
28
+ Rule::BooleanOr,
28
29
  default: Rule::Default
29
30
  )
30
31
  end
@@ -18,7 +18,7 @@ module CodeDrivenDevelopment
18
18
  private
19
19
 
20
20
  def current_indentation
21
- "\t" * @nesting
21
+ " " * @nesting * 2
22
22
  end
23
23
  end
24
24
  end
@@ -0,0 +1,61 @@
1
+ module CodeDrivenDevelopment
2
+ module Rule
3
+ class BooleanOr < AbstractRule
4
+ def capable?
5
+ code.sexp_type == :or &&
6
+ left.sexp_type == :call &&
7
+ right.sexp_type == :call
8
+ end
9
+
10
+ def test
11
+ left_is_true_context = TestComponent::Context.new(%Q("##{left_method_name} is truthy"))
12
+ right_is_true_context = TestComponent::Context.new(%Q("##{left_method_name} is falsey"))
13
+
14
+ left_is_true_context.befores << "allow(obj).to receive(:#{left_method_name}).and_return('#{left_method_name}')"
15
+ left_is_true_context.befores << "allow(obj).to receive(:#{right_method_name})"
16
+
17
+ left_is_true_context << TestComponent::Test.new("returns ##{left_method_name}", [
18
+ "expect(subject).to eq '#{left_method_name}'"
19
+ ])
20
+
21
+ left_is_true_context << TestComponent::Test.new("doesn't call ##{right_method_name}", [
22
+ "subject",
23
+ "expect(obj).not_to have_received :#{right_method_name}"
24
+ ])
25
+
26
+ right_is_true_context.befores << "allow(obj).to receive(:#{left_method_name}).and_return(false)"
27
+ right_is_true_context.befores << "allow(obj).to receive(:#{right_method_name}).and_return('#{right_method_name}')"
28
+
29
+ right_is_true_context << TestComponent::Test.new("returns ##{right_method_name}", [
30
+ "expect(subject).to eq '#{right_method_name}'"
31
+ ])
32
+
33
+ right_is_true_context << TestComponent::Test.new("calls ##{left_method_name}", [
34
+ "subject",
35
+ "expect(obj).to have_received :#{left_method_name}"
36
+ ])
37
+
38
+ test_context << left_is_true_context
39
+ test_context << right_is_true_context
40
+ end
41
+
42
+ private
43
+
44
+ def left
45
+ code[1]
46
+ end
47
+
48
+ def left_method_name
49
+ left[2]
50
+ end
51
+
52
+ def right
53
+ code[2]
54
+ end
55
+
56
+ def right_method_name
57
+ right[2]
58
+ end
59
+ end
60
+ end
61
+ end
@@ -9,7 +9,10 @@ module CodeDrivenDevelopment
9
9
 
10
10
  def test
11
11
  test_context.befores << "allow(#{receiver_value}).to receive :#{method_name}"
12
- body = ["expect(#{receiver_value}).to have_received :#{method_name}"]
12
+ body = [
13
+ "subject",
14
+ "expect(#{receiver_value}).to have_received :#{method_name}"
15
+ ]
13
16
  test_context << TestComponent::Test.new("calls #{receiver_value}.#{method_name}", body)
14
17
  end
15
18
 
@@ -11,7 +11,7 @@ module CodeDrivenDevelopment
11
11
  test_context << new_context
12
12
 
13
13
  # Do this last so that the method invocation is the last line in the before.
14
- new_context.befores << "obj.#{method_name}"
14
+ new_context.subject = "obj.#{method_name}"
15
15
  new_context.lets << TestComponent::Let.new(:obj, "described_class.new")
16
16
  end
17
17
 
@@ -9,7 +9,10 @@ module CodeDrivenDevelopment
9
9
 
10
10
  def test
11
11
  test_context.befores << "allow(#{receiver_value}).to receive :#{method_name}"
12
- body = ["expect(#{receiver_value}).to have_received :#{method_name}"]
12
+ body = [
13
+ "subject",
14
+ "expect(#{receiver_value}).to have_received :#{method_name}"
15
+ ]
13
16
  test_context << TestComponent::Test.new("calls ##{method_name}", body)
14
17
  end
15
18
 
@@ -1,24 +1,26 @@
1
1
  module CodeDrivenDevelopment
2
2
  module TestComponent
3
3
  class Context
4
- def initialize(description = nil, befores = [], tests = [], lets = [])
5
- @description, @befores, @tests, @lets = description, befores, tests, lets
4
+ def initialize(description = nil, befores = [], tests = [], lets = [], subject = nil)
5
+ @description, @befores, @tests, @lets, @subject = description, befores, tests, lets, subject
6
6
  end
7
7
 
8
8
  attr_reader :tests, :befores, :lets
9
- attr_accessor :description
9
+ attr_accessor :description, :subject
10
10
 
11
11
  def << child
12
12
  @tests << child
13
13
  end
14
14
 
15
15
  def indented_output io
16
- io << ""
17
16
  io << "describe #@description do"
18
17
  io.indented do
19
18
  lets.each do |let|
20
19
  let.indented_output(io)
21
20
  end
21
+ if subject
22
+ io << "subject { #{subject} }"
23
+ end
22
24
  if befores.any?
23
25
  io << "before do"
24
26
  io.indented do
@@ -1,3 +1,3 @@
1
1
  module CodeDrivenDevelopment
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -15,6 +15,7 @@ require "code_driven_development/rule/set"
15
15
  require "code_driven_development/rule/constant_method_call"
16
16
  require "code_driven_development/rule/instance_method_call"
17
17
  require "code_driven_development/rule/default"
18
+ require "code_driven_development/rule/boolean_or"
18
19
  require "code_driven_development/rule/class"
19
20
  require "code_driven_development/rule/validation"
20
21
  require "code_driven_development/rule/instance_method"
data/samples/president.rb CHANGED
@@ -7,8 +7,7 @@ class Bunker < ActiveRecord::Base
7
7
  end
8
8
 
9
9
  def alert_president
10
- alert_staff
11
10
  SecretService.stand_down
12
- President.alert
11
+ alert_staff || go_crazy
13
12
  end
14
13
  end
@@ -0,0 +1,54 @@
1
+ -
2
+ title: creates shoulda_matchers
3
+ input: |
4
+ class Lolcat < ActiveRecord::Base
5
+ validate :cuteness, presence: true
6
+ end
7
+ output: |
8
+ describe Lolcat do
9
+ it { should validate_presence_of :cuteness }
10
+ end
11
+ -
12
+ title: instance methods that call constants
13
+ input: |
14
+ class Lolcat
15
+ def i_call_things
16
+ CentralBureaucracy.file_report
17
+ end
18
+ end
19
+ output: |
20
+ describe Lolcat do
21
+
22
+ describe "#i_call_things" do
23
+ let(:obj) { described_class.new }
24
+ before do
25
+ allow(CentralBureaucracy).to receive :file_report
26
+ obj.i_call_things
27
+ end
28
+ it "calls CentralBureaucracy.file_report" do
29
+ expect(CentralBureaucracy).to have_received :file_report
30
+ end
31
+ end
32
+ end
33
+ -
34
+ title: instance methods that call instance methods
35
+ input: |
36
+ class Lolcat
37
+ def i_call_instance_methods
38
+ meth
39
+ end
40
+ end
41
+ output: |
42
+ describe Lolcat do
43
+
44
+ describe "#i_call_instance_methods" do
45
+ let(:obj) { described_class.new }
46
+ before do
47
+ allow(obj).to receive :meth
48
+ obj.i_call_instance_methods
49
+ end
50
+ it "calls #meth" do
51
+ expect(obj).to have_received :meth
52
+ end
53
+ end
54
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,5 @@
1
+ require 'yaml'
1
2
  require_relative '../lib/code_driven_development'
2
- require_relative 'support/have_consecutive_lines_matching_matcher'
3
3
 
4
4
  RSpec.configure do |config|
5
5
  config.expect_with :rspec do |c|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code_driven_development
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Finnie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-03 00:00:00.000000000 Z
11
+ date: 2014-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby_parser
@@ -80,6 +80,34 @@ dependencies:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: cucumber
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: aruba
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  description: Automatically generate stubby tests from your implementation.
84
112
  email:
85
113
  - dan@danfinnie.com
@@ -96,10 +124,13 @@ files:
96
124
  - Rakefile
97
125
  - bin/cdd
98
126
  - code_driven_development.gemspec
127
+ - features/my_feature.feature
128
+ - features/support/aruba.rb
99
129
  - lib/code_driven_development.rb
100
130
  - lib/code_driven_development/code_driven_development.rb
101
131
  - lib/code_driven_development/indented_output.rb
102
132
  - lib/code_driven_development/rule/abstract_rule.rb
133
+ - lib/code_driven_development/rule/boolean_or.rb
103
134
  - lib/code_driven_development/rule/class.rb
104
135
  - lib/code_driven_development/rule/constant_method_call.rb
105
136
  - lib/code_driven_development/rule/default.rb
@@ -114,9 +145,8 @@ files:
114
145
  - lib/code_driven_development/test_component/test.rb
115
146
  - lib/code_driven_development/version.rb
116
147
  - samples/president.rb
117
- - spec/my_spec.rb
148
+ - spec/samples/lone_sample.yaml
118
149
  - spec/spec_helper.rb
119
- - spec/support/have_consecutive_lines_matching_matcher.rb
120
150
  homepage: https://github.com/danfinnie/code-driven-development
121
151
  licenses:
122
152
  - MIT
@@ -143,6 +173,7 @@ specification_version: 4
143
173
  summary: Ever see a test and think, "wow, this test cares a lot about the exact abstract
144
174
  syntax tree of the code?" CDD aims to generate tests like that.
145
175
  test_files:
146
- - spec/my_spec.rb
176
+ - features/my_feature.feature
177
+ - features/support/aruba.rb
178
+ - spec/samples/lone_sample.yaml
147
179
  - spec/spec_helper.rb
148
- - spec/support/have_consecutive_lines_matching_matcher.rb
data/spec/my_spec.rb DELETED
@@ -1,72 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe CodeDrivenDevelopment::CodeDrivenDevelopment do
4
- before do
5
- implementation = <<-EOT
6
- class Lolcat < ActiveRecord::Base
7
- validate :cuteness, presence: true
8
-
9
- def i_call_things
10
- CentralBureaucracy.file_report
11
- end
12
-
13
- def i_call_instance_methods
14
- meth
15
- end
16
-
17
- def weigh_options
18
- should_i_stay || should_i_go
19
- end
20
- end
21
- EOT
22
-
23
- @test = CodeDrivenDevelopment::CodeDrivenDevelopment.new(implementation).test_code
24
- end
25
-
26
- it "puts the model name in the describe description" do
27
- expect(@test).to match /^describe Lolcat do/
28
- end
29
-
30
- it "includes shoulda-matchers for simple validations" do
31
- expect(@test).to match /^\tit.*should.*validate_presence_of.*:cuteness/
32
- end
33
-
34
- it "stubs out method calls to constants" do
35
- expect(@test).to have_consecutive_lines_matching [
36
- /^\tdescribe.*"#i_call_things"/,
37
- /^\t\tbefore/,
38
- /^\t\t\tallow.CentralBureaucracy..to.*receive.*:file_report/,
39
- /^\t\t\tobj.i_call_things/,
40
- /^\t\tit.*calls Central.*do/,
41
- /^\t\t\texpect.CentralBureaucracy..to.*have_received.*:file_report/
42
- ]
43
- end
44
-
45
- it "stubs out instance method calls" do
46
- expect(@test).to have_consecutive_lines_matching [
47
- /^\tdescribe.*"#i_call_instance_methods"/,
48
- /^\t\tlet.:obj.*described_class.new/,
49
- /^\t\tbefore/,
50
- /^\t\t\tallow.obj..to.*receive.*:meth/,
51
- /^\t\t\tobj.i_call_instance_methods/,
52
- /^\t\tit.*calls #meth.*do/,
53
- /^\t\t\texpect.obj..to.*have_received.*:meth/
54
- ]
55
- end
56
-
57
- it "handles ORs with aplomb" do
58
- expect(@test).to have_consecutive_lines_matching [
59
- /^\tdescribe.*"#weigh_options"/,
60
- /^\t\tlet.:obj.*described_class.new/,
61
- /^\t\tbefore/,
62
- /^\t\t\tallow.obj..to.*receive.*:should_i_stay/,
63
- /^\t\t\tallow.obj..to.*receive.*:should_i_go/,
64
- /^\t\tcontext.*when.*should_i_stay.*truthy/,
65
- /^\t\tbefore do/,
66
- /^\t\t\t
67
- /^\t\t\tobj.weigh_options/,
68
- /^\t\tit.*calls #meth.*do/,
69
- /^\t\t\texpect.obj..to.*have_received.*:meth/
70
- ]
71
- end
72
- end
@@ -1,29 +0,0 @@
1
- RSpec::Matchers.define :have_consecutive_lines_matching do |*regexen|
2
- def compute_match(string, regexen)
3
- if regexen.empty?
4
- return [true]
5
- end
6
-
7
- regex = regexen.shift
8
- m = string.match(regex)
9
- if m
10
- remaining = m.post_match
11
- newline_i = remaining.index("\n")+1
12
- remaining = remaining[newline_i..-1]
13
- compute_match(remaining, regexen)
14
- else
15
- return [false, regex, string]
16
- end
17
- end
18
-
19
- match do |actual|
20
- compute_match(actual, regexen.flatten).shift
21
- end
22
-
23
- failure_message_for_should do |actual|
24
- _, failed_regex, failed_string = compute_match(actual, regexen.flatten)
25
- "expected #{failed_regex.inspect} to match #{failed_string.inspect}"
26
- end
27
-
28
- diffable
29
- end