Permalink
Browse files

Version 3.0.0: Pickle and Times split from PSpec

  • Loading branch information...
1 parent cd3e34b commit a0358a4b32ae6aa3e489252bdee5ae71b2d5ac8d Timothy M. Totten committed Feb 17, 2010
Showing with 33 additions and 301 deletions.
  1. +6 −0 Changelog.txt
  2. +17 −24 README.txt
  3. +1 −0 examples/bowling.t
  4. +1 −1 examples/calc.t
  5. +1 −270 lib/PSpec.pm
  6. +1 −1 lib/Story.pm
  7. +1 −0 t/01-times.t
  8. +1 −1 t/story-basic.t
  9. +1 −1 t/story-chain.t
  10. +1 −1 t/story-multiline.t
  11. +1 −1 t/story-outline.t
  12. +1 −1 t/story-table.t
View
@@ -1,3 +1,9 @@
+Version 3.0.0
+ * Split the story handling into its own library: Pickle
+ * Split the 'times' stuff into a Times library.
+ * The 'x' infix operator is no longer exported by default from Times.
+ * Reworked the tests to use the new libraries.
+
Version 2.5.1
* Added an overloaded definition of the 'x' infix operator.
* Fixed the comments for the Cucumber-like functionality.
View
@@ -11,22 +11,30 @@ the one on the front page of the RSpec website.
After making one, I turned my attention to the example on the Cucumber
website, and added a simple story handler to the library.
-The story handler currently handles simple stories, backgrounds,
-and scenario outlines.
+The story handler has been separated out as it's own library (which
+still depends on PSpec) called Pickle.
-There is support for chaining rules. If you want to call another rule
-from a step definition, use: declare "test for $rule";
+Pickle currently handles simple stories, backgrounds, scenario outlines,
+tables, and multiline text.
-There is also tables and multline text support.
+There is also support for chaining rules. If you want to call another rule
+from a step definition, use: declare "test for $rule";
-In addition to the basic testing stuff, the PSpec library also includes some
-utility functionality such as a 'times' operator and .times Int method.
+In addition to the basic testing stuff, the PSpec project also includes some
+utility functionality, mostly separated out into other libraries, such
+as the Times library which provides a 'times' operator and .times Int method.
-Oh and a tag parser method for Str objects (called 'replace-tags').
+Pickle also has a tag parser method for Str objects (called 'replace-tags').
Pass it a hash, and it will replace any instance of <key> with the
mapped value. Useful for templates (and Scenario Outlines.)
-There is an object called Table which is used to prove Cucumber-like tables.
+There is an object called Table which is used by Pickle to provide
+Cucumber-like Tables. It allows multiple "views" of the data from the
+table.
+
+Oh, and for no particular reason whatsoever, there is a reverse polish
+calculator class called Calculator also included, it's used in a few of
+the examples and tests.
~ Usage ~
@@ -85,21 +93,6 @@ PSpec library:
http://huri.net/tech/pspec
-~ TODO ~
-
-I would like to modularlize the PSpec library further, splitting off
-generic functionality into separate libraries, and then splitting off the
-Cubumber-like story functionality into a new library called Pickle.
-
-Pickle will still be a part of the PSpec project, but will be a separate
-library file (which will depend on the PSpec library itself.)
-
-Since this will be such a massive change, which will break any and all
-assumptions of backwards compatibility, it will be released as version 3.0.
-
-It's not high on my priority list, so don't expect it too soon.
-I hope to deliver it in time for Rakudo *'s release in Q2 2010.
-
~ Credits ~
Well, I must send cudos to the original authors of RSpec and Cucumber,
View
@@ -6,6 +6,7 @@ BEGIN { @*INC.unshift('lib'); }
use PSpec;
use Bowling;
+use Times;
## See PSpec for more information on 'describe', 'times' and 'should-be'.
View
@@ -4,7 +4,7 @@ use v6;
BEGIN { @*INC.unshift('lib'); }
-use PSpec;
+use Pickle;
use Calculator;
our $calculator = Calculator.new;
View
@@ -4,45 +4,13 @@
# or: http://github.org/supernovus/PSpec
# -----------------------------------------------------------------------------
-## A times method for Int, as suggested by Carl Masak
-
-class Int is also {
- method times (&code) {
- for ^self { code() }
- }
-}
-
-## A tag replacement parser for Str. Pass it a hash, and optionally
-# a prefix and suffix and it will replace any instances of the keys
-# with the mapped values. Useful for templates!
-# NOTE: This method MODIFIES the String object that calls it, use carefully!
-
-class Str is also {
- method replace-tags (%tags, $prefix='<', $suffix='>') {
- for %tags.kv -> $key, $value {
- self.=subst("$prefix$key$suffix", $value);
- }
- return self;
- }
-}
-
-use Table;
-
-module PSpec:ver<2.5.1>:auth<http://huri.net/>;
+module PSpec:ver<3.0.0>:auth<http://huri.net/>;
our $tests_run = 0;
our $failed_tests = 0;
our $die_on_fail = 0;
our $test_plan = 0;
-sub check-verbose is export(:DEFAULT) {
- my $verbose = 0;
- if @*ARGS[0] ~~ / ^ \- (v+) / {
- $verbose = ~$0.chars;
- }
- return $verbose;
-}
-
# New infix operator: should-be
# Performs a test, and if it fails, lists the value that was returned,
# as well as what was expected. Example:
@@ -107,24 +75,6 @@ sub should-be (Bool $result, Any $got, Any $expected) is export(:DEFAULT) {
return $result;
}
-# New infix operator: times
-# Specify a number, and a block of code. The block of code will be
-# executed the specified number of times.
-# Example: 20 times { say "hello" }
-
-multi sub infix:<times> (Int $num, &closure) is export(:DEFAULT) {
- for ^$num { closure() }
-}
-
-# Overloaded infix operator: x
-# Specify a block of code, x, then an integer.
-# It calls $integer times { block of code }.
-# Example: { say "hello" } x 20
-
-multi sub infix:<x> (&closure, Int $num) is export(:DEFAULT) {
- $num times &closure;
-}
-
# Public function: plan ($number)
# Adds the specified number to the planned number of tests.
# By default the test suites have no plan, so this is optional.
@@ -199,224 +149,5 @@ END {
}
}
-### PickleSandwich (aka Cucumber) functionality below here.
-#
-# I haven't written any documentation for this bit of code yet.
-# See the tests in examples/ and t/ to see how this works.
-
-our $feature_name = '';
-our $scenario_name = '';
-our @call_queue; ## Now we add statements in handlers.
-
-sub declare (Str $line) is export(:DEFAULT) {
- @call_queue.push: $line;
-}
-
-sub split-def ($line) {
- my @def = $line.split(/:s \| /);
- @def.pop; ## Kill the last empty field.
- @def.shift; ## Kill the first empty field.
- return @def;
-}
-
-sub build-fields ($line, @fields) {
- my @temp_fields = split-def $line;
- return @temp_fields.hashMap(@fields);
-}
-
-sub lines-handler (@lines, @handlers) {
- for @lines -> $line {
- line-handler $line, @handlers;
- }
-}
-
-sub line-handler ($line, @handlers) {
- for @handlers -> $handle {
- $handle($line);
- }
-}
-
-## The public story handler function.
-# Calls the private method.
-
-sub handle-story (
- @story,
- :$verbose=check-verbose(),
- Code *@handlers
-) is export(:DEFAULT) {
- story-handler(@story, :verbose($verbose), @handlers);
-}
-
-## A quick way to check verbosity levels.
-
-sub chain-handler (@story, @handlers, $verbose, $min) {
- my $inner_verbose = 0;
- if ($verbose > $min) { $inner_verbose = $verbose; }
- story-handler(@story, :verbose($inner_verbose), @handlers);
-}
-
-## The real story handler.
-sub story-handler (@story, :$verbose=0, @handlers) {
-
- ## For backgrounds
- my $in_background = 0;
- my @background;
-
- ## For tables
- my $previous_line = '';
- my $table = Table.new;
-
- ## For multiline text
- my $multiline = '';
- my @multiline;
- my $line_length = 0;
-
- ## For outlines
- my $outline_name = '';
- my $in_outline = 0;
- my @outline_text;
- my $in_examples = 0;
- my @example_fields;
-
- for @story -> $line {
- if $verbose { diag $line; }
- my $follow_dispatch = 1;
-
- given $line {
- when Table { } # We skip tables. Handle elsewhere.
- when Pair { } # We skip pairs. Handle elsewhere.
- if $in_examples {
- when not /:s ^ \| / {
- $in_examples = 0;
- }
- }
- elsif !$in_outline && !$in_background {
- if $table.key {
- when not /:s ^ \| / {
- line-handler $table, @handlers;
- $table.clear;
- continue;
- }
- }
- if $multiline {
- when /:s ^ \"\"\" $/ {
- ## We've reached the end of the text.
- my $linePair = $multiline => @multiline;
- line-handler $linePair, @handlers;
- @multiline.splice;
- $multiline = '';
- $line_length = 0;
- }
- when not /:s ^ \"\"\" $/ {
- $line.=substr($line_length);
- @multiline.push: $line;
- $follow_dispatch = 0;
- }
- }
- else {
- when /^(<.ws>)\"\"\"<.ws>$/ {
- $line_length = ~$0.chars;
- $follow_dispatch = 0;
- $multiline = $previous_line;
- }
- }
- when /:s ^ \| / {
- $follow_dispatch = 0;
- $table.key = $previous_line if !$table.key;
- my @fields = split-def $line;
- $table.push: \@fields;
- }
- }
- when /:s Feature\: (.*)/ {
- @background.splice; ## Kill existing backgrounds.
- $feature_name = $0;
- $follow_dispatch = 1;
- }
- when /:s Scenario Outline\: (.*)/ {
- @outline_text.splice; ## Make sure this is empty.
- $outline_name = $0;
- $in_outline = 1;
- }
- if ($in_outline) {
- when /:s Examples\:/ {
- @example_fields.splice; ## Make sure this is empty.
- $in_outline = 0;
- $in_examples = 1;
- }
- }
- when /:s Scenario\: (.*)/ {
- $scenario_name = $0;
- $in_background = 0;
- if @background {
- $follow_dispatch = 0; ## No dispatch.
- line-handler $line, @handlers; ## Run this now.
- ## Then run the rest:
- chain-handler @background, @handlers, $verbose, 2;
- }
- }
- when /:s Background\:/ {
- $in_background = 1;
- }
- }
-
- if $in_outline {
- @outline_text.push: $line;
- $follow_dispatch = 0;
- }
-
- if $in_examples && $line ~~ /:s ^ \| / {
- $follow_dispatch = 0;
- if @example_fields {
- my %example = build-fields($line, @example_fields);
- $scenario_name = $outline_name ~ ' # ' ~ $in_examples++;
- line-handler "Subtest: $scenario_name", @handlers;
- my @outline = @outline_text;
- @outline>>.replace-tags(%example);
- chain-handler @outline, @handlers, $verbose, 1;
- }
- else {
- ## Get rid of the first line, it's the Outline statement.
- @outline_text.shift;
- @example_fields = split-def $line;
- }
- }
-
- if $in_background {
- if $line !~~ /:s Background\: / {
- @background.push: $line;
- }
- $follow_dispatch = 0;
- }
-
- if $follow_dispatch {
- line-handler $line, @handlers;
- }
-
- $previous_line = $line;
-
- ## Next up, run anything in the call queue.
- if @call_queue {
- my @chain_story = @call_queue;
- @call_queue.splice;
- chain-handler @chain_story, @handlers, $verbose, 1;
- }
-
- }
-}
-
-sub assert ($condition) is export(:DEFAULT) {
- return ok $condition, "$feature_name: $scenario_name";
-}
-
-## Use for handlers that need to support tables and multiline text.
-
-sub matching ($line) is export(:DEFAULT) {
- my $matcher = $line;
- if $line ~~ Table | Pair {
- $matcher = $line.key;
- }
- return $matcher;
-}
-
## End of library
View
@@ -1,4 +1,4 @@
-use PSpec;
+use Times;
module Story;
View
@@ -5,6 +5,7 @@ use v6;
BEGIN { @*INC.unshift('lib'); }
use PSpec;
+use Times :ALL;
describe "PSpec", "times", [
'operator works' => {
Oops, something went wrong.

0 comments on commit a0358a4

Please sign in to comment.