minitest-given 0.1.pre → 3.0.0.beta.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +27 -0
  4. data/{README.rdoc → MIT-LICENSE} +1 -29
  5. data/README.md +763 -0
  6. data/Rakefile +225 -15
  7. data/TODO +13 -0
  8. data/doc/main.rdoc +7 -0
  9. data/examples/example_helper.rb +10 -0
  10. data/examples/failing/natural_failing_spec.rb +48 -0
  11. data/examples/failing/sample_spec.rb +7 -0
  12. data/examples/integration/and_spec.rb +44 -0
  13. data/examples/integration/failing/eval_subexpression_spec.rb +9 -0
  14. data/examples/integration/failing/module_nesting_spec.rb +13 -0
  15. data/examples/integration/failing/undefined_method_spec.rb +9 -0
  16. data/examples/integration/failing_messages_spec.rb +38 -0
  17. data/examples/integration/focused_line_spec.rb +9 -0
  18. data/examples/integration/given_spec.rb +73 -0
  19. data/examples/integration/invariant_spec.rb +31 -0
  20. data/examples/integration/then_spec.rb +8 -0
  21. data/examples/loader.rb +4 -0
  22. data/examples/minitest_helper.rb +38 -0
  23. data/examples/other/line_example.rb +9 -0
  24. data/examples/stack/stack.rb +29 -0
  25. data/examples/stack/stack_spec.rb +60 -0
  26. data/examples/stack/stack_spec1.rb +3 -0
  27. data/lib/given.rb +2 -0
  28. data/lib/minitest/given.rb +1 -32
  29. data/lib/minitest-given.rb +9 -1
  30. data/rakelib/bundler_fix.rb +17 -0
  31. data/rakelib/gemspec.rake +161 -0
  32. data/rakelib/metrics.rake +30 -0
  33. data/rakelib/preview.rake +14 -0
  34. data/test/before_test.rb +22 -0
  35. data/test/meme_test.rb +36 -0
  36. metadata +69 -85
  37. data/.autotest +0 -23
  38. data/.gemtest +0 -0
  39. data/CHANGELOG.rdoc +0 -3
  40. data/Manifest.txt +0 -11
  41. data/minitest-given.gemspec +0 -42
  42. data/test/test_assertions.rb +0 -30
  43. data/test/test_comparison.rb +0 -25
  44. data/test/test_version.rb +0 -10
data/Rakefile CHANGED
@@ -1,21 +1,231 @@
1
- require "rubygems"
2
- require "hoe"
1
+ #!/usr/bin/ruby -wKU
3
2
 
4
- Hoe.plugin :gemspec
5
- Hoe.plugin :git
6
- Hoe.plugin :minitest
3
+ require 'rake/clean'
4
+ require './lib/given/version'
5
+ require './lib/given/module_methods'
7
6
 
8
- Hoe.spec "minitest-given" do
9
- developer "Mike Moore", "mike@blowmage.com"
7
+ CLEAN.include("pkg/rspec-given-*").exclude("pkg/*.gem")
8
+ CLOBBER.include("*.gemspec", "html", "README", "README.old")
10
9
 
11
- self.summary = "Given/When/Then for minitest"
12
- self.description = "Adds Given/When/Then built on top of minitest's spec DSL."
13
- self.urls = ["http://blowmage.com/minitest-given"]
10
+ # README Formatting --------------------------------------------------
14
11
 
15
- self.history_file = "CHANGELOG.rdoc"
16
- self.readme_file = "README.rdoc"
17
- self.testlib = :minitest
12
+ task :default => :examples
18
13
 
19
- dependency "minitest", ">= 4.4.0"
20
- dependency "wrong", ">= 0.6.3"
14
+ def version
15
+ Given::VERSION
16
+ end
17
+
18
+ def tag_name
19
+ "rspec-given-#{version}"
20
+ end
21
+
22
+ def tagged?
23
+ `git tag`.split.include?(tag_name)
24
+ end
25
+
26
+ def git_clean?
27
+ sh "git status | grep 'nothing to commit'", :verbose => false do |status|
28
+ return status
29
+ end
30
+ end
31
+
32
+ desc "Display the current version tag"
33
+ task :version do
34
+ puts tag_name
35
+ end
36
+
37
+ desc "Tag the current commit with #{tag_name}"
38
+ task :tag do
39
+ fail "Cannot tag, project directory is not clean" unless git_clean?
40
+ fail "Cannot tag, #{tag_name} already exists." if tagged?
41
+ sh "git tag #{tag_name}"
42
+ end
43
+
44
+ # Running examples ---------------------------------------------------
45
+
46
+ desc "Run all the examples"
47
+ task :examples => [:specs, :rs_examples]
48
+
49
+ desc "Run the RSpec 2 specs and examples"
50
+ task :examples => [:specs, :rs_examples, :mt_examples]
51
+
52
+ desc "Run the specs"
53
+ task :specs do
54
+ puts "Running specs"
55
+ sh "rspec spec"
56
+ end
57
+
58
+ EXAMPLES = FileList['examples/**/*_spec.rb'].
59
+ exclude('examples/failing/*.rb').
60
+ exclude('examples/integration/failing/*.rb')
61
+
62
+ unless Given::NATURAL_ASSERTIONS_SUPPORTED
63
+ EXAMPLES.exclude("examples/stack/*.rb")
64
+ end
65
+
66
+ FAILING_EXAMPLES = FileList['examples/failing/**/*_spec.rb']
67
+
68
+ desc "Run the RSpec specs and examples"
69
+ task :rs => [:specs, :rs_examples]
70
+
71
+ desc "Run the Minitest tests and examples"
72
+ task :mt => [:specs, :mt_examples]
73
+
74
+ desc "Run the examples in RSpec 2"
75
+ task :rs_examples => [:verify_rspec2] do
76
+ puts "Running examples (with RSpec2)"
77
+ sh "rspec #{EXAMPLES}"
78
+ end
79
+
80
+ desc "Run the examples in Minitest"
81
+ task :mt_examples do
82
+ puts "Running examples (with Minitest)"
83
+ sh "ruby -Ilib:examples examples/loader.rb #{EXAMPLES}"
84
+ end
85
+
86
+ desc "Run failing examples"
87
+ task :failing => [:verify_rspec2] do
88
+ puts "Running failing examples (with RSpec2)"
89
+ sh "rspec #{FAILING_EXAMPLES}"
90
+ end
91
+
92
+ task :verify_rspec1 do
93
+ sh "type spec >/dev/null 2>&1", :verbose => false do |status|
94
+ fail "You need to install RSpec 1 in order to test against it." unless status
95
+ end
96
+ end
97
+
98
+ task :verify_rspec2 do
99
+ sh "type rspec >/dev/null 2>&1", :verbose => false do |status|
100
+ fail "You need to install RSpec 2 in order to test against it." unless status
101
+ end
102
+ end
103
+
104
+ task :load_check do
105
+ SRC_FILES = FileList['lib/rspec/given/*.rb'].exclude(%r(rspec1))
106
+ SRC_FILES.each do |fn|
107
+ sh %{ruby -Ilib -e 'load "#{fn}"'}
108
+ end
109
+ end
110
+
111
+ # Formatting the README ----------------------------------------------
112
+
113
+ directory 'html'
114
+
115
+ desc "Display the README file"
116
+ task :readme => ["README.md"] do
117
+ Bundler.with_clean_env do
118
+ sh "ghpreview README.md"
119
+ end
120
+ end
121
+
122
+ desc "Generate an RDoc README"
123
+ file "README.md" => ["examples/stack/stack_spec.rb", "lib/given/version.rb"] do
124
+ open("README.md") do |ins|
125
+ open("README.tmp", "w") do |outs|
126
+ state = :copy
127
+ while line = ins.gets
128
+ case state
129
+ when :copy
130
+ if line =~ /rspec-given, version +\d+(\.(\d+|beta))+/i
131
+ line.gsub!(/version +\d+(\.(\d+|beta))+/i, "version #{Given::VERSION}")
132
+ outs.puts line
133
+ elsif line =~ /^<pre>/
134
+ state = :insert
135
+ else
136
+ outs.puts line
137
+ end
138
+ when :insert
139
+ outs.puts "<pre>"
140
+ outs.puts open("examples/stack/stack_spec.rb") { |codes| codes.read }
141
+ outs.puts "</pre>"
142
+ state = :skip
143
+ when :skip
144
+ state = :copy2 if line =~ /^<\/pre>/
145
+ when :copy2
146
+ outs.puts line
147
+ end
148
+ end
149
+ end
150
+ end
151
+ mv "README.md", "README.old"
152
+ mv "README.tmp", "README.md"
153
+ end
154
+
155
+
156
+ # RDoc ---------------------------------------------------------------
157
+ begin
158
+ require 'rdoc/task'
159
+ if RDoc::VERSION > "2.4.2"
160
+ RDOC_ENABLED = true
161
+ else
162
+ puts "Version of RDoc is too old, please gem install a later version"
163
+ RDOC_ENABLED = false
164
+ end
165
+ rescue LoadError => ex
166
+ RDOC_ENABLED = false
167
+ end
168
+
169
+ begin
170
+ require 'darkfish-rdoc'
171
+ DARKFISH_ENABLED = true
172
+ rescue LoadError => ex
173
+ DARKFISH_ENABLED = false
174
+ end
175
+
176
+ if RDOC_ENABLED
177
+ def md_to_rdoc(infile, outfile)
178
+ open(infile) do |ins|
179
+ open(outfile, "w") do |outs|
180
+ state = :copy
181
+ while line = ins.gets
182
+ case state
183
+ when :ignore
184
+ if line =~ /^-->/
185
+ state = :copy
186
+ end
187
+ when :pre
188
+ if line =~ /^<\/pre>/
189
+ state = :copy
190
+ else
191
+ outs.puts " #{line}"
192
+ end
193
+ when :copy
194
+ if line =~ /^<!--/
195
+ state = :ignore
196
+ elsif line =~ /^<pre>/
197
+ state = :pre
198
+ else
199
+ line.gsub!(/^####/, '====')
200
+ line.gsub!(/^###/, '===')
201
+ line.gsub!(/^##/, '==')
202
+ line.gsub!(/^#/, '=')
203
+ outs.puts line
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ file "README" => ["README.md"] do
212
+ md_to_rdoc("README.md", "README")
213
+ end
214
+
215
+ RDoc::Task.new("rdoc") do |rdoc|
216
+ rdoc.rdoc_dir = 'html'
217
+ rdoc.title = "RSpec/Given -- A Given/When/Then extension for RSpec"
218
+ rdoc.options = [
219
+ '--line-numbers',
220
+ '--main' , 'doc/main.rdoc',
221
+ '--title', 'Given - Given/When/Then Extensions for RSpec'
222
+ ]
223
+ rdoc.options << '-SHN' << '-f' << 'darkfish' if DARKFISH_ENABLED
224
+
225
+ rdoc.rdoc_files.include('README')
226
+ rdoc.rdoc_files.include('MIT-LICENSE')
227
+ rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
228
+ end
229
+
230
+ task :rdoc => "README"
21
231
  end
data/TODO ADDED
@@ -0,0 +1,13 @@
1
+ Things to do to improve the minitest integration
2
+
3
+ TODO:
4
+
5
+ * Make a separate gem for minitest (do we need one for given-core?)
6
+
7
+ DONE:
8
+
9
+ * Handle have_failed in minitest
10
+ * General cleanup making sure files go where they need.
11
+ * Implement assertion counting for minitest
12
+ * Figure out why the minitest example count is so low.
13
+ * Move stuff out of minitest_helper to appropriate file.
data/doc/main.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ = Given/When/Then for RSpec
2
+
3
+ rspec-given is an RSpec extension to allow Given/When/Then notation in
4
+ RSpec specifications. It is a natural extension of the experimental
5
+ work done on the Given framework.
6
+
7
+ For more information see http://github.com/jimweirich/rspec-given
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH << './examples/stack'
2
+
3
+ if defined?(RSpec)
4
+ require 'rspec/given'
5
+ require 'spec_helper'
6
+ else
7
+ require 'minitest/autorun'
8
+ require 'minitest/given'
9
+ require 'minitest_helper'
10
+ end
@@ -0,0 +1,48 @@
1
+ require 'rspec/given'
2
+ require 'rspec/given/natural_assertion'
3
+
4
+ describe "Natural Assertions" do
5
+ use_natural_assertions
6
+
7
+ Given(:foo) { 1 }
8
+ Given(:expected) { 2 }
9
+ Given(:ary) { [1] }
10
+ Given(:empty) { [] }
11
+ Given(:null) { nil }
12
+ Then { foo+foo+2*foo == expected }
13
+ Then { nil == "HI" && true && :symbol && 1}
14
+ Then { foo.should == 2 }
15
+ Then { foo != 1 }
16
+ Then { foo.should_not == 1 }
17
+ Then { foo.should be_nil }
18
+ Then { ary.empty? }
19
+ Then { !null.nil? }
20
+ Then { fail "OUCH" }
21
+ Then { ! empty.empty? }
22
+ Then {
23
+ (puts "Ha ha world", ! true)
24
+ }
25
+
26
+ Then { Math.sqrt(10) == about(3.1623).percent(0.0001) }
27
+
28
+ describe "Error Examples" do
29
+ When(:result) { fail "OUCH" }
30
+ Then { result == :ok }
31
+ end
32
+
33
+ describe "Non-Error Failures" do
34
+ When(:result) { :ok }
35
+ Then { result == have_failed(StandardError, /^O/) }
36
+ end
37
+
38
+ context "Incorrect non-idempotent conditions" do
39
+ Given(:ary) { [1, 2, 3] }
40
+ Then { ary.delete(1) == nil }
41
+ end
42
+
43
+ context "Correct idempotent conditions" do
44
+ Given(:ary) { [1, 2, 3] }
45
+ When(:result) { ary.delete(1) }
46
+ Then { result == nil }
47
+ end
48
+ end
@@ -0,0 +1,7 @@
1
+ require 'rspec/given'
2
+
3
+ describe "Natural Assertions" do
4
+ Given(:foo) { 1 }
5
+ Given(:bar) { 2 }
6
+ Then { foo + bar == 2 }
7
+ end
@@ -0,0 +1,44 @@
1
+ require 'example_helper'
2
+
3
+ describe "And" do
4
+
5
+ Given(:info) { [] }
6
+
7
+ describe "And is called after Then" do
8
+ Then { info << "T" }
9
+ And { info << "A" }
10
+ And { given_assert_equal ["T", "A"], info }
11
+ end
12
+
13
+ describe "And is called only once with multiple Thens" do
14
+ Then { info << "T" }
15
+ Then { info << "T2" }
16
+ And { given_assert(info == ["T"] || info == ["T2"]) }
17
+ end
18
+
19
+ describe "Inherited Ands are not run" do
20
+ Then { info << "T-OUTER" }
21
+ And { info << "A-OUTER" }
22
+ And { given_assert_equal ["T-OUTER", "A-OUTER"], info }
23
+
24
+ context "inner" do
25
+ Then { info << "T-INNER" }
26
+ And { info << "A-INNER" }
27
+ And { given_assert_equal ["T-INNER", "A-INNER"], info }
28
+ end
29
+ end
30
+
31
+ describe "Ands require a Then" do
32
+ begin
33
+ And { }
34
+ rescue StandardError => ex
35
+ @message = ex.message
36
+ end
37
+
38
+ it "should define a message" do
39
+ message = self.class.instance_eval { @message }
40
+ given_assert_match(/and.*without.*then/i, message)
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,9 @@
1
+ require 'rspec/given'
2
+
3
+ describe "Then with nesting" do
4
+ use_natural_assertions
5
+ Given(:index) { 1 }
6
+ Given(:value) { "X" }
7
+ Given(:array) { ["a", "b", "c"] }
8
+ Then { array[index].upcase == value }
9
+ end
@@ -0,0 +1,13 @@
1
+ require 'rspec/given'
2
+
3
+ module Nesting
4
+ X = 1
5
+ end
6
+
7
+ module Nesting
8
+ describe "Then with nesting" do
9
+ use_natural_assertions
10
+ Given(:z) { 2 }
11
+ Then { X == z }
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ require 'rspec/given'
2
+
3
+ describe "Then with nesting" do
4
+ use_natural_assertions
5
+ def self.xyz
6
+ nil
7
+ end
8
+ Then { xyz }
9
+ end
@@ -0,0 +1,38 @@
1
+ require 'example_helper'
2
+ require 'open3'
3
+
4
+ describe "Failing Messages" do
5
+ use_natural_assertions_if_supported
6
+
7
+ IOS = Struct.new(:out, :err)
8
+
9
+ def run_spec(filename)
10
+ inn, out, err, wait = Open3.popen3("rspec", "examples/integration/failing/#{filename}")
11
+ IOS.new(out.read, err.read)
12
+ end
13
+
14
+ When(:ios) { run_spec(failing_test) }
15
+
16
+ context "when referencing constants from nested modules" do
17
+ Given(:failing_test) { "module_nesting_spec.rb" }
18
+ Then { ios.err == "" }
19
+ And { ios.out !~ /uninitialized constant RSpec::Given::InstanceExtensions::X/ }
20
+ end
21
+
22
+ context "when referencing undefined methods" do
23
+ Given(:failing_test) { "undefined_method_spec.rb" }
24
+ Then { ios.err == "" }
25
+ And { ios.out =~ /undefined local variable or method `xyz'/ }
26
+ end
27
+
28
+ context "when breaking down expressions" do
29
+ Given(:failing_test) { "eval_subexpression_spec.rb" }
30
+ Then { ios.err == "" }
31
+ And { ios.out =~ /false *<- array\[index\]\.upcase == value$/ }
32
+ And { ios.out =~ /"B" *<- array\[index\].upcase$/ }
33
+ And { ios.out =~ /"b" *<- array\[index\]$/ }
34
+ And { ios.out =~ /\["a", "b", "c"\] *<- array$/ }
35
+ And { ios.out =~ /1 *<- index$/ }
36
+ And { ios.out =~ /"X" *<- value$/ }
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ require 'example_helper'
2
+
3
+ describe "Focused Line" do
4
+ it "runs only a single test" do
5
+ ENV['FRAMEWORK'] = nil
6
+ output = `rspec examples/other/line_example.rb:7`
7
+ given_assert_not_match(/FIRST/, output)
8
+ end
9
+ end
@@ -0,0 +1,73 @@
1
+ require 'example_helper'
2
+
3
+ describe "Running Givens before Whens" do
4
+ Given(:info) { [] }
5
+ Given { info << "outer1" }
6
+ Given { info << "outer2" }
7
+
8
+ context "using a when without result" do
9
+ When { info << "when" }
10
+
11
+ context "inner with When" do
12
+ Given { info << "inner1" }
13
+ Given { info << "inner2" }
14
+ Then { given_assert_equal ["outer1", "outer2", "inner1", "inner2", "when"], info }
15
+
16
+ context "using a nested When" do
17
+ When { info << "when2" }
18
+ Then { given_assert_equal ["outer1", "outer2", "inner1", "inner2", "when", "when2"], info}
19
+ end
20
+
21
+ context "using two nested When" do
22
+ When { info << "when2a" }
23
+ When { info << "when2b" }
24
+ Then {
25
+ given_assert_equal ["outer1", "outer2", "inner1", "inner2", "when", "when2a", "when2b"], info
26
+ }
27
+ end
28
+ end
29
+ end
30
+
31
+ context "using a when with a result" do
32
+ When(:result) { info << "when" }
33
+
34
+ context "inner with when" do
35
+ Given { info << "inner1" }
36
+ Given { info << "inner2" }
37
+ Then { given_assert_equal ["outer1", "outer2", "inner1", "inner2", "when"], info }
38
+ end
39
+ end
40
+
41
+ context "using no whens" do
42
+ Given { info << "inner1" }
43
+ Given { info << "inner2" }
44
+ Then { given_assert_equal ["outer1", "outer2", "inner1", "inner2"], info }
45
+ end
46
+ end
47
+
48
+ describe "Lazy Givens" do
49
+ Given(:bomb) { fail StandardError, "SHOULD NEVER BE CALLED" }
50
+
51
+ context "when called" do
52
+ Then {
53
+ given_assert_raises(StandardError, /NEVER/) { bomb }
54
+ }
55
+ end
56
+
57
+ context "when not called" do
58
+ Given(:value) { :ok }
59
+ Then { given_assert_equal :ok, value }
60
+ end
61
+ end
62
+
63
+ describe "Non-Lazy Givens" do
64
+ Given(:info) { [] }
65
+
66
+ When { info << :when }
67
+
68
+ context "inner" do
69
+ Given!(:a) { info << :given; "A VALUE" }
70
+ Then { given_assert_equal [:given, :when], info }
71
+ end
72
+
73
+ end
@@ -0,0 +1,31 @@
1
+ require 'example_helper'
2
+
3
+ describe "Invariants" do
4
+ Given(:info) { [] }
5
+
6
+ Invariant { info << "I1" }
7
+
8
+ Then { given_assert_equal ["I1"], info }
9
+
10
+ context "with nested invariants" do
11
+ Invariant { info << "I2" }
12
+
13
+ Then { given_assert_equal ["I1", "I2"], info }
14
+ end
15
+
16
+ context "with multiple invariants" do
17
+ Invariant { info << "I2a" }
18
+ Invariant { info << "I2b" }
19
+
20
+ Then { given_assert_equal ["I1", "I2a", "I2b"], info }
21
+ end
22
+
23
+ context "with a when" do
24
+ Invariant { info << "I2" }
25
+
26
+ When(:when_info) { info.dup }
27
+
28
+ Then { given_assert_equal ["I1", "I2"], info }
29
+ Then { given_assert_equal [], when_info }
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ require 'example_helper'
2
+
3
+ describe "Then" do
4
+ context "empty thens with natural assertions" do
5
+ use_natural_assertions_if_supported
6
+ Then { }
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ ARGV.each do |fn|
2
+ puts "Loading #{fn} ..."
3
+ load fn
4
+ end
@@ -0,0 +1,38 @@
1
+
2
+ module GivenAssertions
3
+ def given_assert(cond)
4
+ assert cond
5
+ end
6
+
7
+ def given_assert_equal(expected, actual)
8
+ actual.must_equal(expected)
9
+ end
10
+
11
+ def given_assert_match(pattern, actual)
12
+ actual.must_match(pattern)
13
+ end
14
+
15
+ def given_assert_not_match(pattern, actual)
16
+ actual.wont_match(pattern)
17
+ end
18
+
19
+ def given_assert_raises(error, pattern=//, &block)
20
+ ex = assert_raises(error, &block)
21
+ ex.message.must_match(pattern)
22
+ end
23
+ end
24
+
25
+ module NaturalAssertionControl
26
+ def use_natural_assertions_if_supported(enabled=true)
27
+ if enabled && ! Given::NATURAL_ASSERTIONS_SUPPORTED
28
+ Given {
29
+ skip "Natural assertions are not supported in JRuby"
30
+ }
31
+ else
32
+ use_natural_assertions(enabled)
33
+ end
34
+ end
35
+ end
36
+
37
+ Minitest::Spec.send(:include, GivenAssertions)
38
+ include NaturalAssertionControl
@@ -0,0 +1,9 @@
1
+ require 'example_helper'
2
+
3
+ describe "Line Spec" do
4
+
5
+ Then { puts "FIRST" }
6
+
7
+ Then { puts "SECOND" }
8
+
9
+ end
@@ -0,0 +1,29 @@
1
+ class Stack
2
+ class StackError < StandardError; end
3
+ class UnderflowError < StackError; end
4
+
5
+ def initialize
6
+ @items = []
7
+ end
8
+
9
+ def depth
10
+ @items.size
11
+ end
12
+
13
+ def empty?
14
+ @items.empty?
15
+ end
16
+
17
+ def top
18
+ @items.last
19
+ end
20
+
21
+ def push(item)
22
+ @items << item
23
+ end
24
+
25
+ def pop
26
+ fail UnderflowError, "Cannot pop an empty stack" if empty?
27
+ @items.pop
28
+ end
29
+ end