tryouts 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -1,6 +1,22 @@
1
1
  TRYOUTS, CHANGES
2
2
 
3
3
 
4
+ #### 0.6.4 (2009-06-25) ###############################
5
+
6
+ NOTE: command testing (:cli) is still disabled.
7
+
8
+ * FIXED: Stash wasn't being displayed in the drill report
9
+ * CHANGE: CLI is now formatted to be 80 characters wide.
10
+ * ADDED: Tryouts::Drill::Sergeant::Benchmark
11
+ * ADDED: Tryouts::Stats
12
+ * ADDED: new dream formats: :mean and :sdev which compare with <=.
13
+ dream 10, :mean
14
+ drill "do something" do; ...; end # stats.mean <= 10
15
+ * ADDED: new dream format: :proc
16
+ dream lambda { |x| x.real < 0.1 }, :proc
17
+ drill("array sort!") { @@array.dup.sort! }
18
+
19
+
4
20
  #### 0.6.3 (2009-06-25) ###############################
5
21
 
6
22
  NOTE: command testing (:cli) is still disabled.
data/README.rdoc CHANGED
@@ -1,47 +1,104 @@
1
- = Tryouts - v0.6 BETA
1
+ = Tryouts - v0.7 BETA
2
2
 
3
- Tryouts is a high-level testing library for your command-line applications and Ruby codes.
3
+ Tryouts is a high-level testing library (DSL) for your Ruby codes.
4
4
 
5
- NOTE: The DSL syntax has changed significantly from 0.5 and command-line app tests are currently disabled.
6
-
7
- == Syntax
8
-
9
- Tryouts is a bit different than other testing libraries. Test definitions are organized in a similar way as Shoulda tests (although the keywords in the syntax are different).
5
+ A tryout is made up of one of more drills. The return value of the drill block is compared to the expectations defined by one or more dreams. The goal is to achieve your dreams.
10
6
 
11
7
  === Terminology
12
8
 
13
- * Tryout: a set of drills (just like basketball tryouts is a set of drills)
9
+ * Tryout: a set of drills (think: basketball tryouts)
14
10
  * Drill: a single test.
15
- * Dream: the expected outcome of a drill. There's always one or more dream per drill.
11
+ * Drill Sergeant: The class responsible for executing a drill.
12
+ * Dream: the expected outcome of a drill. There's always one or more dream per drill.
13
+
14
+ == Installation ==
16
15
 
17
- == Testing Ruby codes (an API)
16
+ {{{
17
+ $ gem install tryouts
18
+ }}}
18
19
 
19
- Tryouts employs the same approach for testing Ruby codes. The return value of the drill block is compared to the expectation defined by the dream. Here is an example of including dreams inside the tryout definition.
20
+ == Examples
21
+
22
+ The examples below are a complete overview of Tryouts syntax.
23
+
24
+ === Testing Ruby Codes (:api)
20
25
 
21
26
  library :caesars, "../path/to/caesars/lib"
22
27
 
23
- tryout "Common Usage" do
24
- dream 3
25
- drill "Check the return value" do
28
+ tryouts "Common Usage" do
29
+
30
+ # This drill block should return 3.
31
+ drill "Maths R Us", 3 do
26
32
  12 / 4
27
33
  end
28
-
29
- dream :Proc, :class
30
- drill "Check the return value class" do
31
- Proc.new do
32
- :anything
33
- end
34
+
35
+ # You can specify a method to execute
36
+ # on the return value of the drill block.
37
+ drill "We want a symbol", Symbol, :class do
38
+ orange.methods.first
34
39
  end
35
40
 
41
+ # Dreams can also be specified explicitly which is
42
+ # important b/c it's possible to specify multiple.
43
+ dream Array, :class
44
+ dream [:a, :b, :c]
45
+ drill "Should return a list of 3" do
46
+ Letters.list(3)
47
+ end
48
+
49
+ # Drills can pass based on an exception too.
36
50
  dream NameError, :exception
37
- drill "A test can pass based on the exception" do
51
+ drill "Something failed" do
38
52
  raise NameError
39
53
  end
40
54
 
41
- dream /\w\d\w \d\w\d/, :match
42
- drill "Knows where Santa Claus lives", 'H0H 0H0'
55
+ # We can even put simple drills on a single line.
56
+ drill "Santa's postal code", 'H0H 0H0', /\w\d\w \d\w\d/, :match
57
+
43
58
  end
44
59
 
60
+ === Benchmarks (:benchmark)
61
+
62
+ You can also use Tryouts to run benchmarks. The tryouts method takes a second parameter which specifies which drill sergeant to use. Below we specify <tt>:benchmark</tt> so each drill is timed and executed multiple times.
63
+
64
+ tryouts "Benchmark examples", :benchmark do
65
+
66
+ # We create an Array and store it in a class
67
+ # variable so it's available to other drills.
68
+ drill "Create test array" do
69
+ @@array = (1..100000).map { rand }
70
+ end
71
+
72
+ dream 3.0, :mean # The mean should be <= 3.0 seconds
73
+ dream 0.1, :sdev # and the standard deviation <= 0.1
74
+ drill("Array sort!") { @@array.dup.sort! }
75
+
76
+ # You can also include a dream inline
77
+ drill("Array sort", 3.0, :mean) { @@array.dup.sort }
78
+
79
+ # The 3rd argument is the number of times to
80
+ # execute the drill block. The mean and sdev
81
+ # are calculate based on all iterations. The
82
+ # default is 5 and the maximum is 30.
83
+ dream 0.1, :sdev, 15
84
+ drill("Array sort") { @@array.dup.sort }
85
+
86
+ end
87
+
88
+ The drill blocks in a benchmark Tryout return Tryouts::Stats objects. See: Tryouts::Drill::Sergeant::Benchmark
89
+
90
+ == Screenshots
91
+
92
+ Here is an example of Tryouts output from a gibbler[http://github.com/delano/gibbler/blob/gibbler-0.2.1/tryouts/gibbler_tryouts.rb] tryout:
93
+
94
+ http://github.com/delano/tryouts/raw/gh-pages/screens/tryouts-1-failure.png
95
+
96
+ The drill that failed looks like this:
97
+
98
+ dream :to_gibble, :respond_to?
99
+ dream 'ab33b9dec202d136d0e695a3a7b06ee678134882', :to_gibble
100
+ drill "Array", Array
101
+
45
102
 
46
103
  == BETA Notice
47
104
 
@@ -53,22 +110,28 @@ This library is very new (est. 2009-05-19) and has not been vetted by the scruti
53
110
 
54
111
  == On Threads
55
112
 
56
- Tryouts does some funky stuff to make it simple to write tests. This "funky stuff" means that this library is *not thread-safe at definition-time*. However, once all tryouts files are parsed (or in OO-syntax, once all objects are created), this class should be *thread-safe at drill-time*.
113
+ Tryouts does some funky stuff to make it simple to write tests. This "funky stuff" means that this library is <em>not thread-safe at definition-time</em>. However, once all tryouts files are parsed (or in OO-syntax, once all objects are created), this class should be <em>thread-safe at drill-time</em>.
114
+
57
115
 
58
116
  == More Info
59
117
 
60
118
  * Check out the sourcecodes[http://github.com/delano/tryouts]
61
119
  * Read the rdocs[http://tryouts.rubyforge.org/]
62
120
  * About Solutious[http://solutious.com/about/]
121
+ * Inspiration[http://www.youtube.com/watch?v=iB9nhyosDVs]
122
+
63
123
 
64
124
  == Thanks
65
125
 
66
- * Everyone at Utrecht.rb and Amsterdam.rb
126
+ * Everyone at Utrecht.rb and Amsterdam.rb for putting up with my Ruby questions :]
127
+ * Sam Aaron (http://sam.aaron.name) for the early feedback.
128
+
67
129
 
68
130
  == Credits
69
131
 
70
132
  * Delano (@solutious.com)
71
133
 
134
+
72
135
  == Related Projects
73
136
 
74
137
  * Context[http://github.com/jeremymcanally/context/tree/master]
@@ -47,13 +47,13 @@ class Run < Drydock::Command
47
47
 
48
48
  passed, failed = 0, 0
49
49
  Tryouts.instances.each_pair do |group,tryouts_inst|
50
- puts '', ' %-60s'.att(:reverse) % group unless Tryouts.verbose < 0
50
+ puts '', ' %-80s'.att(:reverse) % group unless Tryouts.verbose < 0
51
51
  puts " #{tryouts_inst.paths.join("\n ")}" if Tryouts.verbose > 0
52
52
  tryouts_inst.tryouts.each_pair do |name,to|
53
53
  begin
54
54
  to.run
55
55
  to.report
56
- rescue SyntaxError, LoadError, Exception,
56
+ rescue SyntaxError, LoadError, Exception, TypeError,
57
57
  RuntimeError, NoMethodError, NameError => ex
58
58
  tryouts_inst.errors << ex
59
59
  end
@@ -63,12 +63,13 @@ class Run < Drydock::Command
63
63
  end
64
64
 
65
65
  unless tryouts_inst.errors.empty?
66
- title = '%-61s' % " RUNTIME ERRORS !?"
67
- puts $/, title.color(:red).att(:reverse).bright
66
+ title = '%-79s' % " RUNTIME ERRORS !?"
67
+ puts $/, ' ' << title.color(:red).att(:reverse).bright
68
68
  tryouts_inst.errors.each do |ex|
69
- trace = Tryouts.verbose > 0 ? ex.backtrace : [ex.backtrace.first]
70
- puts '%12s: %s (%s)' % ["error", ex.message.inspect, ex.class]
71
- puts '%12s: %s' % ["trace", trace.join($/ + ' '*14)]
69
+ trace = Tryouts.verbose > 1 ? ex.backtrace : [ex.backtrace.first]
70
+ puts '%14s: %s' % [ex.class, ex.message.to_s.split($/).join($/ + ' '*16)]
71
+ puts
72
+ puts '%14s %s' % ["", trace.join($/ + ' '*16)]
72
73
  puts
73
74
  end
74
75
  end
@@ -27,6 +27,11 @@ class Tryouts::Drill
27
27
  when :match
28
28
  reality.output.respond_to?(:match) &&
29
29
  !reality.output.match(dream.output).nil?
30
+ when :proc
31
+ dream.output.is_a?(Proc) &&
32
+ reality.comparison_value(dream) == dream.comparison_value
33
+ when :mean, :sdev
34
+ reality.comparison_value(dream) <= dream.comparison_value
30
35
  when :gt
31
36
  reality.output > dream.output
32
37
  when :gte
@@ -66,8 +71,13 @@ class Tryouts::Drill
66
71
 
67
72
  begin
68
73
  case dream.format
74
+ when :proc
75
+ test = dream.output
76
+ test.arity > 0 ? "Proc.call(reality) == true" : "Proc.call == true"
69
77
  when :exception
70
78
  "#{reality.etype} == #{dream.output}"
79
+ when :mean, :sdev
80
+ "#{reality.comparison_value(dream)} <= #{dream.output}"
71
81
  when :match
72
82
  "#{reality.output.inspect}.match(#{dream.output.inspect})"
73
83
  when :gt, :gte, :lt, :lte, :ne
@@ -139,6 +149,11 @@ class Tryouts::Drill
139
149
  def comparison_value
140
150
  return @ret unless @ret.nil?
141
151
  @ret = case @format
152
+ when :gt, :gte, :lt, :lte, :ne
153
+ op = {:gt=>'>',:gte=>'>=', :lt=>'<', :lte => '<=', :ne => '!='}.find { |i| i[0] == @format }
154
+ @output
155
+ when :proc
156
+ true
142
157
  when :respond_to?, :is_a?, :kind_of?
143
158
  true
144
159
  else
@@ -168,6 +183,9 @@ class Tryouts::Drill
168
183
 
169
184
  def comparison_value(dream)
170
185
  case dream.format
186
+ when :proc
187
+ test = dream.output
188
+ (test.arity > 0 ? test.call(@output) : test.call)
171
189
  when :exception
172
190
  @etype
173
191
  when :respond_to?, :is_a?, :kind_of?
data/lib/tryouts/drill.rb CHANGED
@@ -12,6 +12,8 @@ class Tryouts
12
12
  require 'tryouts/drill/response'
13
13
  require 'tryouts/drill/sergeant/cli'
14
14
  require 'tryouts/drill/sergeant/api'
15
+ require 'tryouts/drill/sergeant/benchmark'
16
+ require 'tryouts/drill/sergeant/rbenchmark'
15
17
 
16
18
  class NoSergeant < Tryouts::Exception; end
17
19
  class UnknownFormat < Tryouts::Exception; end
@@ -29,27 +31,40 @@ class Tryouts
29
31
  attr_reader :dreams
30
32
  # A Reality object (the actual output of the test)
31
33
  attr_reader :reality
32
-
34
+
35
+ @@valid_dtypes = [:cli, :api, :benchmark]
36
+
33
37
  def initialize(name, dtype, *args, &drill)
34
38
  @name, @dtype, @drill, @skip = name, dtype, drill, false
35
39
  @dreams = []
36
- if @dtype == :cli
40
+ case @dtype
41
+ when :cli
37
42
  @sergeant = Tryouts::Drill::Sergeant::CLI.new *args
38
- elsif @dtype == :api
43
+ when :api
39
44
  default_output = drill.nil? ? args.shift : nil
40
45
  @sergeant = Tryouts::Drill::Sergeant::API.new default_output
41
46
  @dreams << Tryouts::Drill::Dream.new(*args) unless args.empty?
42
- elsif @dtype == :skip
47
+ when :benchmark
48
+ default_output, format, reps = *args
49
+ @sergeant = Tryouts::Drill::Sergeant::Benchmark.new reps || 1
50
+ @dreams << Tryouts::Drill::Dream.new(Tryouts::Stats, :class)
51
+ unless default_output.nil?
52
+ @dreams << Tryouts::Drill::Dream.new(default_output, format)
53
+ end
54
+ when :skip
43
55
  @skip = true
44
56
  else
45
57
  raise NoSergeant, "Weird drill sergeant: #{@dtype}"
46
58
  end
59
+ @clr = :red
47
60
  # For CLI drills, a block takes precedence over inline args.
48
61
  # A block will contain multiple shell commands (see Rye::Box#batch)
49
62
  drill_args = [] if dtype == :cli && drill.is_a?(Proc)
50
63
  @reality = Tryouts::Drill::Reality.new
51
64
  end
52
65
 
66
+ def self.valid_dtype?(t); @@valid_dtypes.member?(t); end
67
+
53
68
  def skip?; @skip; end
54
69
 
55
70
  def run(context=nil)
@@ -69,6 +84,69 @@ class Tryouts
69
84
  self.success?
70
85
  end
71
86
 
87
+ def flag
88
+ if skip?
89
+ "SKIP"
90
+ elsif success?
91
+ "PASS".color(@clr).bright
92
+ else
93
+ note = @dreams.empty? ? '[nodream]' : ''
94
+ "FAIL #{note}".color(@clr).bright
95
+ end
96
+ end
97
+
98
+ def info
99
+ out = StringIO.new
100
+ if Tryouts.verbose > 1
101
+ if @dreams.empty?
102
+ out.puts '%6s%s'.color(@clr) % ['', @reality.output.inspect]
103
+ else
104
+ @dreams.each do |dream|
105
+ if dream != @reality
106
+ out.puts '%6s%s'.color(:red) % ['', @reality.output.inspect]
107
+ else
108
+ out.puts '%6s%s'.color(:green) % ["", dream.test_to_string(@reality)]
109
+ end
110
+ end
111
+ end
112
+ elsif Tryouts.verbose > 0
113
+ out.puts '%6s%s'.color(@clr) % ['', @reality.output.inspect]
114
+ unless @reality.stash.empty?
115
+ @reality.stash.each_pair do |n,v|
116
+ out.puts '%18s: %s'.color(@clr) % [n,v.inspect]
117
+ end
118
+ out.puts
119
+ end
120
+ end
121
+ out.rewind
122
+ out.read
123
+ end
124
+
125
+ def report
126
+ return if skip?
127
+ out = StringIO.new
128
+
129
+ @dreams.each do |dream|
130
+ next if dream == reality #? :normal : :red
131
+ out.puts '%12s: %s'.color(@clr) % ["drill", dream.test_to_string(@reality)]
132
+ out.puts '%12s: %s' % ["returned", @reality.comparison_value(dream).inspect]
133
+ out.puts '%12s: %s' % ["expected", dream.comparison_value.inspect]
134
+ out.puts
135
+ end
136
+
137
+ unless @reality.error.nil?
138
+ out.puts '%14s: %s' % [@reality.etype, @reality.error.to_s.split($/).join($/ + ' '*16)]
139
+ end
140
+ unless @reality.trace.nil?
141
+ trace = Tryouts.verbose > 1 ? @reality.trace : [@reality.trace.first]
142
+ out.puts '%14s %s' % ['', trace.join($/ + ' '*16)]
143
+ out.puts
144
+ end
145
+
146
+ out.rewind
147
+ out.read
148
+ end
149
+
72
150
  def success?
73
151
  return false if @dreams.empty? && @reality.output != true
74
152
  begin
@@ -77,6 +155,7 @@ class Tryouts
77
155
  puts ex.message, ex.backtrace if Tryouts.debug?
78
156
  return false
79
157
  end
158
+ @clr = :green
80
159
  true
81
160
  end
82
161
 
@@ -30,11 +30,10 @@ class Tryouts
30
30
  # A Hash of Dream objects for this Tryout. The keys are drill names.
31
31
  attr_reader :dream_catcher
32
32
 
33
- @@valid_dtypes = [:cli, :api]
34
33
 
35
34
  def initialize(name, dtype, command=nil, *args)
36
35
  raise "Must supply command for dtype :cli" if dtype == :cli && command.nil?
37
- raise "#{dtype} is not a valid drill type" if !@@valid_dtypes.member?(dtype)
36
+ raise "#{dtype} is not a valid drill type" if !Drill.valid_dtype?(dtype)
38
37
  @name, @dtype, @command = name, dtype, command
39
38
  @drills, @dream_catcher = [], []
40
39
  @passed, @failed, @skipped = 0, 0, 0
@@ -56,36 +55,19 @@ class Tryouts
56
55
  # Execute all Drill objects
57
56
  def run
58
57
  DrillContext.module_eval &setup if setup.is_a?(Proc)
59
- puts Tryouts::TRYOUT_MSG.bright % @name unless Tryouts.verbose < 0
58
+ puts "\n %s ".bright % @name unless Tryouts.verbose < 0
60
59
  @drills.each do |drill|
61
- print Tryouts::DRILL_MSG % drill.name unless Tryouts.verbose < 0
60
+ print ' %-70s ' % "\"#{drill.name}\"" unless Tryouts.verbose < 0
61
+ drill.run DrillContext.new
62
62
  if drill.skip?
63
- puts "SKIP" if Tryouts.verbose >= 0
64
- puts if Tryouts.verbose > 0
65
63
  @skipped += 1
66
- next
67
- end
68
- drill.run DrillContext.new
69
- drill.success? ? @passed += 1 : @failed += 1
70
- next if Tryouts.verbose < 0
71
- note = drill.dreams.empty? ? '[nodream]' : ''
72
- c = drill.success? ? :green : :red
73
- puts drill.success? ? "PASS".color(c).bright : "FAIL #{note}".color(c).bright
74
- if Tryouts.verbose > 1
75
- if drill.dreams.empty?
76
- puts '%6s%s'.color(c) % ['', drill.reality.output.inspect]
77
- else
78
- drill.dreams.each do |dream|
79
- if dream != drill.reality
80
- puts '%6s%s'.color(c) % ['', drill.reality.output.inspect]
81
- else
82
- puts '%6s%s'.color(:green) % ["", dream.test_to_string(drill.reality)]
83
- end
84
- end
85
- end
86
- elsif Tryouts.verbose > 0
87
- puts '%6s%s'.color(c) % ['', drill.reality.output.inspect]
64
+ elsif drill.success?
65
+ @passed += 1
66
+ else
67
+ @failed += 1
88
68
  end
69
+ puts drill.flag # PASS, FAIL, SKIP
70
+ puts drill.info if Tryouts.verbose > 0 && !drill.skip?
89
71
  end
90
72
  DrillContext.module_eval &clean if clean.is_a?(Proc)
91
73
  end
@@ -93,40 +75,12 @@ class Tryouts
93
75
  # Prints error output. If there are no errors, it prints nothing.
94
76
  def report
95
77
  return if Tryouts.verbose < 0
96
- return true if success?
97
78
  failed = @drills.select { |d| !d.skip? && !d.success? }
98
79
  failed.each_with_index do |drill,index|
99
- dreams, reality = drill.dreams, drill.reality
100
-
101
- unless dreams.empty?
102
- title = ' %-51s %2d/%-2d ' % [drill.name, index+1, failed.size]
103
- puts $/, ' ' << title.color(:red).att(:reverse)
104
-
105
- drill.reality.stash.each_pair do |n,v|
106
- puts '%14s: %s' % [n,v.inspect]
107
- end
108
-
109
- dreams.each do |dream|
110
- next if dream == reality #? :normal : :red
111
- puts '%12s: %s'.color(:red) % ["test", dream.test_to_string(drill.reality)]
112
- puts '%12s: %s' % ["returned", reality.comparison_value(dream).inspect]
113
- puts '%12s: %s' % ["expected", dream.comparison_value.inspect]
114
- puts
115
- end
116
-
117
- end
118
-
119
- unless reality.error.nil?
120
- puts '%12s: %s (%s)' % ["error", reality.error.inspect, reality.etype]
121
- end
122
- unless reality.trace.nil?
123
- trace = Tryouts.verbose > 1 ? reality.trace : [reality.trace.first]
124
- puts '%12s: %s' % ["trace", trace.join($/ + ' '*14)]
125
- puts
126
- end
127
-
80
+ title = ' %-70s %2d/%-2d ' % ["\"#{drill.name}\"", index+1, failed.size]
81
+ puts $/, ' ' << title.color(:red).att(:reverse)
82
+ puts drill.report
128
83
  end
129
- false
130
84
  end
131
85
 
132
86
  # Did every Tryout finish successfully?
data/lib/tryouts.rb CHANGED
@@ -32,18 +32,15 @@ class Tryouts
32
32
  # Raised when there is a problem loading or parsing a Tryouts::Drill::Dream object
33
33
  class BadDreams < Exception; end
34
34
 
35
- VERSION = "0.6.3"
35
+ VERSION = "0.7.0"
36
36
 
37
37
  require 'tryouts/mixins'
38
38
  require 'tryouts/tryout'
39
39
  require 'tryouts/drill'
40
+ require 'tryouts/stats'
40
41
 
41
42
  require 'tryouts/orderedhash'
42
43
  HASH_TYPE = (RUBY_VERSION =~ /1.9/) ? ::Hash : Tryouts::OrderedHash
43
-
44
- TRYOUT_MSG = "\n %s "
45
- DRILL_MSG = ' %-50s '
46
- DRILL_ERR = ' %s: '
47
44
 
48
45
  # An Array of +_tryouts.rb+ file paths that have been loaded.
49
46
  @@loaded_files = []
@@ -142,7 +139,7 @@ class Tryouts
142
139
  $LOAD_PATH.unshift path unless path.nil?
143
140
  begin
144
141
  require @library.to_s
145
- rescue SyntaxError, LoadError, Exception,
142
+ rescue SyntaxError, LoadError, Exception, TypeError,
146
143
  RuntimeError, NoMethodError, NameError => ex
147
144
  @errors << ex
148
145
  Tryouts.failed = true
@@ -191,7 +188,7 @@ class Tryouts
191
188
  # Process the rest of the DSL
192
189
  begin
193
190
  to.from_block block if block
194
- rescue SyntaxError, LoadError, Exception,
191
+ rescue SyntaxError, LoadError, Exception, TypeError,
195
192
  RuntimeError, NoMethodError, NameError => ex
196
193
  @errors << ex
197
194
  Tryouts.failed = true
@@ -252,7 +249,7 @@ class Tryouts
252
249
  to.instance_eval file_content, fpath
253
250
  end
254
251
  to.paths << fpath
255
- rescue SyntaxError, LoadError, Exception,
252
+ rescue SyntaxError, LoadError, Exception, TypeError,
256
253
  RuntimeError, NoMethodError, NameError => ex
257
254
  to.errors << ex
258
255
  Tryouts.failed = true
data/tryouts.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "tryouts"
3
3
  s.rubyforge_project = "tryouts"
4
- s.version = "0.6.3"
4
+ s.version = "0.7.0"
5
5
  s.summary = "Tryouts are high-level tests for your Ruby code. May all your dreams come true!"
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tryouts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum