aslakhellesoy-cucumber 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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