aslakhellesoy-cucumber 0.0.1

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 (74) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +73 -0
  4. data/README.txt +78 -0
  5. data/Rakefile +4 -0
  6. data/bin/cucumber +3 -0
  7. data/config/hoe.rb +70 -0
  8. data/config/requirements.rb +15 -0
  9. data/examples/Rakefile +7 -0
  10. data/examples/pure_ruby/addition.rb +16 -0
  11. data/examples/pure_ruby/steps/addition_steps.rb +43 -0
  12. data/examples/simple/addition.story +12 -0
  13. data/examples/simple/division.story +17 -0
  14. data/examples/simple/steps/addition_steps.rb +43 -0
  15. data/examples/simple_norwegian/steg/matte_steg.rb.rb +31 -0
  16. data/examples/simple_norwegian/summering.story +10 -0
  17. data/examples/web/run_stories.story +10 -0
  18. data/examples/web/steps/stories_steps.rb +39 -0
  19. data/gem_tasks/deployment.rake +34 -0
  20. data/gem_tasks/environment.rake +7 -0
  21. data/gem_tasks/fix_cr_lf.rake +10 -0
  22. data/gem_tasks/rspec.rake +21 -0
  23. data/gem_tasks/treetop.rake +33 -0
  24. data/gem_tasks/website.rake +17 -0
  25. data/lib/cucumber.rb +17 -0
  26. data/lib/cucumber/cli.rb +118 -0
  27. data/lib/cucumber/core_ext/proc.rb +35 -0
  28. data/lib/cucumber/core_ext/string.rb +17 -0
  29. data/lib/cucumber/executor.rb +85 -0
  30. data/lib/cucumber/formatters.rb +1 -0
  31. data/lib/cucumber/formatters/ansicolor.rb +89 -0
  32. data/lib/cucumber/formatters/html_formatter.rb +271 -0
  33. data/lib/cucumber/formatters/pretty_formatter.rb +66 -0
  34. data/lib/cucumber/formatters/progress_formatter.rb +41 -0
  35. data/lib/cucumber/parser/languages.yml +35 -0
  36. data/lib/cucumber/parser/nodes.rb +88 -0
  37. data/lib/cucumber/parser/story_parser.rb +13 -0
  38. data/lib/cucumber/parser/story_parser.treetop.erb +41 -0
  39. data/lib/cucumber/parser/story_parser_en.rb +554 -0
  40. data/lib/cucumber/parser/story_parser_fr.rb +554 -0
  41. data/lib/cucumber/parser/story_parser_no.rb +554 -0
  42. data/lib/cucumber/parser/story_parser_pt.rb +554 -0
  43. data/lib/cucumber/parser/top_down_visitor.rb +26 -0
  44. data/lib/cucumber/rails/world.rb +69 -0
  45. data/lib/cucumber/rake/task.rb +74 -0
  46. data/lib/cucumber/ruby_tree.rb +14 -0
  47. data/lib/cucumber/ruby_tree/nodes.rb +68 -0
  48. data/lib/cucumber/step_methods.rb +39 -0
  49. data/lib/cucumber/step_mother.rb +38 -0
  50. data/lib/cucumber/tree.rb +127 -0
  51. data/lib/cucumber/version.rb +9 -0
  52. data/script/console +10 -0
  53. data/script/console.cmd +1 -0
  54. data/script/destroy +14 -0
  55. data/script/destroy.cmd +1 -0
  56. data/script/generate +14 -0
  57. data/script/generate.cmd +1 -0
  58. data/script/txt2html +74 -0
  59. data/script/txt2html.cmd +1 -0
  60. data/setup.rb +1585 -0
  61. data/spec/cucumber/core_ext/string_spec.rb +20 -0
  62. data/spec/cucumber/executor_spec.rb +55 -0
  63. data/spec/cucumber/formatters/ansicolor_spec.rb +18 -0
  64. data/spec/cucumber/formatters/html_formatter_spec.rb +59 -0
  65. data/spec/cucumber/formatters/stories.html +274 -0
  66. data/spec/cucumber/sell_cucumbers.story +9 -0
  67. data/spec/spec.opts +2 -0
  68. data/spec/spec_helper.rb +7 -0
  69. data/website/index.html +11 -0
  70. data/website/index.txt +39 -0
  71. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  72. data/website/stylesheets/screen.css +138 -0
  73. data/website/template.html.erb +48 -0
  74. metadata +157 -0
@@ -0,0 +1,10 @@
1
+ Historie: Addition
2
+ Som en matteidiot
3
+ Vil jeg bli fortalt summen av to tall
4
+ Slik at jeg ikke gjør dumme feil
5
+
6
+ Scenario: 5+7
7
+ Gitt at jeg har tastet inn 5
8
+ Og at jeg har tastet inn 7
9
+ Når jeg summerer
10
+ Så skal resultatet være 12
@@ -0,0 +1,10 @@
1
+ Story: Run Stories
2
+ As an information seeker
3
+ I want to find more information
4
+ So that I can learn more
5
+
6
+ Scenario: Find what I'm looking for
7
+ Given I am on the search page
8
+ And I have entered "rspec"
9
+ When I search
10
+ Then I should see a link to "RSpec-1.1.3: Overview":http://rspec.info/
@@ -0,0 +1,39 @@
1
+ require 'spec'
2
+
3
+ case PLATFORM
4
+ when /darwin/
5
+ require 'safariwatir'
6
+ Browser = Watir::Safari
7
+ when /win32/
8
+ require 'watir'
9
+ Browser = Watir::IE
10
+ when /java/
11
+ require 'celerity'
12
+ Browser = Celerity::Browser
13
+ else
14
+ raise "Can't do web stories on #{PLATFORM}"
15
+ end
16
+
17
+ Before do
18
+ @b = Browser.new
19
+ end
20
+
21
+ After do
22
+ @b.close
23
+ end
24
+
25
+ Given 'I am on the search page' do
26
+ @b.goto 'http://www.google.com/'
27
+ end
28
+
29
+ Given /I have entered "(.*)"/ do |query|
30
+ @b.text_field(:name, 'q').set(query)
31
+ end
32
+
33
+ When 'I search' do
34
+ @b.button(:name, 'btnG').click
35
+ end
36
+
37
+ Then /I should see a link to "(.*)":(.*)/ do |text, url|
38
+ @b.link(:url, url).text.should == text
39
+ end
@@ -0,0 +1,34 @@
1
+ desc 'Release the website and new gem version'
2
+ task :deploy => [:check_version, :website, :release] do
3
+ puts "Remember to create SVN tag:"
4
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
5
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
6
+ puts "Suggested comment:"
7
+ puts "Tagging release #{CHANGES}"
8
+ end
9
+
10
+ desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
11
+ task :local_deploy => [:website_generate, :install_gem]
12
+
13
+ task :check_version do
14
+ unless ENV['VERSION']
15
+ puts 'Must pass a VERSION=x.y.z release version'
16
+ exit
17
+ end
18
+ unless ENV['VERSION'] == VERS
19
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
20
+ exit
21
+ end
22
+ end
23
+
24
+ desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
25
+ task :install_gem_no_doc => [:clean, :package] do
26
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
27
+ end
28
+
29
+ namespace :manifest do
30
+ desc 'Recreate Manifest.txt to include ALL files'
31
+ task :refresh do
32
+ `rake check_manifest | patch -p0 > Manifest.txt`
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ task :ruby_env do
2
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
3
+ "jruby"
4
+ else
5
+ "ruby"
6
+ end unless defined? RUBY_APP
7
+ end
@@ -0,0 +1,10 @@
1
+ desc 'Make all files use UNIX (\n) line endings'
2
+ task :fix_cr_lf do
3
+ files = FileList['**/*']
4
+ files.each do |f|
5
+ next if File.directory?(f)
6
+ s = IO.read(f)
7
+ s.gsub!(/\r?\n/, "\n")
8
+ File.open(f, "w") { |io| io.write(s) }
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
@@ -0,0 +1,33 @@
1
+ class StoryCompiler
2
+ def compile
3
+ require 'yaml'
4
+ require 'erb'
5
+ tt = PLATFORM =~ /win32/ ? 'tt.bat' : 'tt'
6
+ template = ERB.new(IO.read(File.dirname(__FILE__) + '/../lib/cucumber/parser/story_parser.treetop.erb'))
7
+ langs = YAML.load_file(File.dirname(__FILE__) + '/../lib/cucumber/parser/languages.yml')
8
+ langs.each do |lang, words|
9
+ grammar_file = File.dirname(__FILE__) + "/../lib/cucumber/parser/story_parser_#{lang}.treetop"
10
+
11
+ STDOUT.write("Generating and compiling grammar for #{lang}...")
12
+ grammar = template.result(binding)
13
+
14
+ # http://groups.google.com/group/treetop-dev/browse_thread/thread/c8a8ced33da07f73
15
+ # http://github.com/vic/treetop/commit/5cec030a1c363e06783f98e4b45ce6ab121996ab
16
+ grammar = "module Cucumber\nmodule Parser\n#{grammar}\nend\nend"
17
+
18
+ File.open(grammar_file, "wb") do |io|
19
+ io.write(grammar)
20
+ end
21
+ system "#{tt} #{grammar_file}"
22
+ FileUtils.rm(grammar_file)
23
+ STDOUT.puts("Done!")
24
+ end
25
+ end
26
+ end
27
+
28
+ namespace :treetop do
29
+ desc 'Compile the grammar'
30
+ task :compile do
31
+ StoryCompiler.new.compile
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ desc 'Generate website files'
2
+ task :website_generate => :ruby_env do
3
+ (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
4
+ sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
5
+ end
6
+ end
7
+
8
+ desc 'Upload website files to rubyforge'
9
+ task :website_upload do
10
+ host = "#{rubyforge_username}@rubyforge.org"
11
+ remote_dir = "/var/www/gforge-projects/#{PATH}/"
12
+ local_dir = 'website'
13
+ sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
14
+ end
15
+
16
+ desc 'Generate and upload website files'
17
+ task :website => [:website_generate, :website_upload, :publish_docs]
@@ -0,0 +1,17 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+ require 'rubygems'
4
+ require 'treetop/runtime'
5
+ require 'treetop/ruby_extensions'
6
+ require 'cucumber/version'
7
+ require 'cucumber/step_methods'
8
+ require 'cucumber/ruby_tree'
9
+ require 'cucumber/executor'
10
+ require 'cucumber/step_mother'
11
+ require 'cucumber/formatters'
12
+ require 'cucumber/parser/story_parser'
13
+ require 'cucumber/cli'
14
+
15
+ module Cucumber
16
+
17
+ end
@@ -0,0 +1,118 @@
1
+ require 'optparse'
2
+ require 'cucumber'
3
+
4
+ module Cucumber
5
+ class CLI
6
+ class << self
7
+ attr_writer :step_mother, :stories
8
+
9
+ def execute
10
+ @execute_called = true
11
+ parse(ARGV).execute!(@step_mother, @stories)
12
+ end
13
+
14
+ def execute_called?
15
+ @execute_called
16
+ end
17
+
18
+ def parse(args)
19
+ cli = new(args)
20
+ cli.parse_options!
21
+ cli
22
+ end
23
+ end
24
+
25
+ def initialize(args)
26
+ @args = args.dup
27
+ @args.extend(OptionParser::Arguable)
28
+ end
29
+
30
+ def parse_options!
31
+ @options = { :require => nil, :lang => 'en', :format => 'pretty', :dry_run => false }
32
+ @args.options do |opts|
33
+ opts.banner = "Usage: cucumber [options] FILES|DIRS"
34
+ opts.on("-r LIBRARY|DIR", "--require LIBRARY|DIR", "Require files before executing the stories.",
35
+ "If this option is not specified, all *.rb files that",
36
+ "are siblings or below the stories will be autorequired") do |v|
37
+ @options[:require] ||= []
38
+ @options[:require] << v
39
+ end
40
+ opts.on("-l LINE", "--line LANG", "Only execute the scenario at the given line") do |v|
41
+ @options[:line] = v
42
+ end
43
+ opts.on("-a LANG", "--language LANG", "Specify language for stories (Default: #{@options[:lang]})") do |v|
44
+ @options[:lang] = v
45
+ end
46
+ opts.on("-f FORMAT", "--format FORMAT", "How to format stories (Default: #{@options[:format]})") do |v|
47
+ @options[:format] = v
48
+ end
49
+ opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.") do
50
+ @options[:dry_run] = true
51
+ end
52
+ end.parse!
53
+ # Whatever is left after option parsing
54
+ @files = @args.map do |path|
55
+ path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
56
+ File.directory?(path) ? Dir["#{path}/**/*.story"] : path
57
+ end.flatten
58
+ end
59
+
60
+ def execute!(step_mother, stories)
61
+ $executor = Executor.new(formatter, step_mother)
62
+ require_files
63
+ load_plain_text_stories(stories)
64
+ $executor.line = @options[:line].to_i if @options[:line]
65
+ $executor.visit_stories(stories)
66
+ exit 1 if $executor.failed
67
+ end
68
+
69
+ private
70
+
71
+ # Requires files - typically step files and ruby story files.
72
+ def require_files
73
+ require "cucumber/parser/story_parser_#{@options[:lang]}"
74
+ requires = @options[:require] || @args.map{|f| File.directory?(f) ? f : File.dirname(f)}.uniq
75
+ libs = requires.map do |path|
76
+ path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
77
+ File.directory?(path) ? Dir["#{path}/**/*.rb"] : path
78
+ end.flatten
79
+ libs.each do |lib|
80
+ begin
81
+ require lib
82
+ rescue LoadError => e
83
+ e.message << "\nFailed to load #{lib}"
84
+ raise e
85
+ end
86
+ end
87
+ end
88
+
89
+ def load_plain_text_stories(stories)
90
+ parser = Parser::StoryParser.new
91
+ @files.each do |f|
92
+ stories << Parser::StoryNode.parse(f, parser)
93
+ end
94
+ end
95
+
96
+ def formatter
97
+ klass = {
98
+ 'progress' => Formatters::ProgressFormatter,
99
+ 'html' => Formatters::HtmlFormatter,
100
+ 'pretty' => Formatters::PrettyFormatter,
101
+ }[@options[:format]]
102
+ klass.new(STDOUT)
103
+ end
104
+
105
+ end
106
+ end
107
+
108
+ # Hook the toplevel StepMother to the CLI
109
+ # TODO: Hook in a RubyStories object on toplevel for pure ruby stories
110
+ extend Cucumber::StepMethods
111
+ Cucumber::CLI.step_mother = step_mother
112
+
113
+ extend(Cucumber::RubyTree)
114
+ Cucumber::CLI.stories = stories
115
+
116
+ at_exit do
117
+ Cucumber::CLI.execute unless Cucumber::CLI.execute_called?
118
+ end
@@ -0,0 +1,35 @@
1
+ module Cucumber
2
+ module CoreExt
3
+ # Proc extension that allows a proc to be called in the context of any object.
4
+ # Also makes it possible to tack a name onto a Proc.
5
+ module CallIn
6
+ attr_accessor :name
7
+
8
+ def call_in(obj, *args, &proc)
9
+ obj.extend(mod)
10
+ # raise ArgCountError.new("The #{name} block takes #{arity2} arguments, but there are #{args.length} matched variables") if args.length != arity2
11
+ obj.__send__(meth, *args, &proc)
12
+ end
13
+
14
+ def arity2
15
+ arity == -1 ? 0 : arity
16
+ end
17
+
18
+ def backtrace_line
19
+ inspect.match(/[\d\w]+@(.*)>/)[1] + ":in `#{name}'"
20
+ end
21
+
22
+ def meth
23
+ @meth ||= "__cucumber_#{object_id}"
24
+ end
25
+
26
+ def mod
27
+ p = self
28
+ m = meth
29
+ @mod ||= Module.new do
30
+ define_method(m, &p)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,17 @@
1
+ class String
2
+ def gzub(pattern, format=nil, &proc)
3
+ s = dup
4
+ md = match(pattern)
5
+ pos = 0
6
+ md.captures.each_with_index do |m, n|
7
+ replacement = if block_given?
8
+ proc.call(m)
9
+ else
10
+ format % m
11
+ end
12
+ s[md.offset(n+1)[0] + pos, m.length] = replacement
13
+ pos += replacement.length - m.length
14
+ end
15
+ s
16
+ end
17
+ end
@@ -0,0 +1,85 @@
1
+ require 'cucumber/core_ext/proc'
2
+
3
+ module Cucumber
4
+ class Pending < StandardError
5
+ end
6
+
7
+ class ArgCountError < StandardError
8
+ end
9
+
10
+ class Executor
11
+ attr_reader :failed
12
+
13
+ def line=(line)
14
+ @line = line
15
+ end
16
+
17
+ def initialize(formatter, step_mother)
18
+ @formatter = formatter
19
+ @world_proc = lambda{ Object.new }
20
+ @before_procs = []
21
+ @after_procs = []
22
+ @step_mother = step_mother
23
+ end
24
+
25
+ def register_world_proc(&proc)
26
+ @world_proc = proc
27
+ end
28
+
29
+ def register_before_proc(&proc)
30
+ proc.extend(CoreExt::CallIn)
31
+ @before_procs << proc
32
+ end
33
+
34
+ def register_after_proc(&proc)
35
+ proc.extend(CoreExt::CallIn)
36
+ @after_procs << proc
37
+ end
38
+
39
+ def visit_stories(stories)
40
+ raise "Line number can only be specified when there is 1 story. There were #{stories.length}." if @line && stories.length != 1
41
+ @step_mother.visit_stories(stories)
42
+ @formatter.visit_stories(stories) if @formatter.respond_to?(:visit_stories)
43
+ stories.accept(self)
44
+ @formatter.dump
45
+ end
46
+
47
+ def visit_story(story)
48
+ story.accept(self)
49
+ end
50
+
51
+ def visit_header(header)
52
+ @formatter.header_executing(header) if @formatter.respond_to?(:header_executing)
53
+ end
54
+
55
+ def visit_narrative(narrative)
56
+ @formatter.narrative_executing(narrative) if @formatter.respond_to?(:narrative_executing)
57
+ end
58
+
59
+ def visit_scenario(scenario)
60
+ if @line.nil? || scenario.at_line?(@line)
61
+ @error = nil
62
+ @world = @world_proc.call
63
+ @formatter.scenario_executing(scenario) if @formatter.respond_to?(:scenario_executing)
64
+ @before_procs.each{|p| p.call_in(@world, *[])}
65
+ scenario.accept(self)
66
+ @after_procs.each{|p| p.call_in(@world, *[])}
67
+ end
68
+ end
69
+
70
+ def visit_step(step)
71
+ if @error.nil?
72
+ begin
73
+ step.execute_in(@world)
74
+ rescue Pending => ignore
75
+ rescue => e
76
+ @failed = true
77
+ @error = e
78
+ end
79
+ @formatter.step_executed(step)
80
+ else
81
+ @formatter.step_skipped(step)
82
+ end
83
+ end
84
+ end
85
+ end