cucumber 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/History.txt +25 -4
  2. data/VERSION.yml +1 -1
  3. data/cucumber.gemspec +33 -29
  4. data/examples/i18n/{cat → ca}/Rakefile +0 -0
  5. data/examples/i18n/{cat → ca}/features/step_definitons/calculator_steps.rb +0 -0
  6. data/examples/i18n/{cat → ca}/features/suma.feature +1 -1
  7. data/examples/i18n/{cat → ca}/lib/calculadora.rb +0 -0
  8. data/examples/i18n/{se → sr-Cyrl}/Rakefile +0 -0
  9. data/examples/i18n/{sr → sr-Cyrl}/features/sabiranje.feature +1 -1
  10. data/examples/i18n/{sr → sr-Cyrl}/features/step_definitons/calculator_steps.rb +0 -0
  11. data/examples/i18n/{sr → sr-Cyrl}/features/support/env.rb +0 -0
  12. data/examples/i18n/{sr-latn → sr-Cyrl}/lib/calculator.rb +0 -0
  13. data/examples/i18n/{sr-latn → sr-Latn}/Rakefile +0 -0
  14. data/examples/i18n/{sr-latn → sr-Latn}/features/sabiranje.feature +0 -0
  15. data/examples/i18n/{sr-latn → sr-Latn}/features/step_definitons/calculator_steps.rb +0 -0
  16. data/examples/i18n/{sr → sr-Latn}/lib/calculator.rb +0 -0
  17. data/examples/i18n/{sr → sv}/Rakefile +0 -0
  18. data/examples/i18n/{se → sv}/features/step_definitons/kalkulator_steps.rb +0 -0
  19. data/examples/i18n/{se → sv}/features/summering.feature +1 -1
  20. data/examples/i18n/{se → sv}/lib/kalkulator.rb +0 -0
  21. data/features/announce.feature +27 -5
  22. data/features/bug_585_tab_indentation.feature +22 -0
  23. data/features/exception_in_after_block.feature +25 -0
  24. data/features/exception_in_before_block.feature +21 -0
  25. data/features/language_help.feature +6 -6
  26. data/features/snippets_when_using_star_keyword.feature +36 -0
  27. data/features/wire_protocol_tags.feature +50 -10
  28. data/gem_tasks/contributors.rake +4 -2
  29. data/lib/autotest/cucumber_rails_rspec2.rb +6 -0
  30. data/lib/autotest/cucumber_rspec2.rb +6 -0
  31. data/lib/cucumber/ast/outline_table.rb +8 -0
  32. data/lib/cucumber/ast/py_string.rb +5 -1
  33. data/lib/cucumber/ast/step_invocation.rb +2 -2
  34. data/lib/cucumber/cli/options.rb +1 -0
  35. data/lib/cucumber/cli/profile_loader.rb +8 -2
  36. data/lib/cucumber/formatter/pdf.rb +9 -2
  37. data/lib/cucumber/formatter/progress.rb +24 -2
  38. data/lib/cucumber/formatter/unicode.rb +11 -11
  39. data/lib/cucumber/languages.yml +14 -13
  40. data/lib/cucumber/parser/feature.rb +0 -257
  41. data/lib/cucumber/parser/feature.tt +0 -32
  42. data/lib/cucumber/parser/i18n.tt +2 -1
  43. data/lib/cucumber/parser/natural_language.rb +7 -4
  44. data/lib/cucumber/parser/py_string.rb +2 -2
  45. data/lib/cucumber/parser/py_string.tt +2 -2
  46. data/lib/cucumber/rb_support/rb_world.rb +9 -0
  47. data/lib/cucumber/step_mother.rb +3 -3
  48. data/spec/cucumber/ast/feature_factory.rb +1 -1
  49. data/spec/cucumber/ast/py_string_spec.rb +4 -4
  50. data/spec/cucumber/ast/step_spec.rb +1 -1
  51. data/spec/cucumber/cli/configuration_spec.rb +7 -0
  52. data/spec/cucumber/cli/profile_loader_spec.rb +29 -4
  53. data/spec/cucumber/step_mother_spec.rb +13 -3
  54. metadata +34 -30
@@ -5,7 +5,15 @@ Feature: Wire protocol tags
5
5
 
6
6
  Background:
7
7
  Given a standard Cucumber project directory structure
8
- And a file named "features/wired.feature" with:
8
+ And a file named "features/step_definitions/some_remote_place.wire" with:
9
+ """
10
+ host: localhost
11
+ port: 54321
12
+
13
+ """
14
+
15
+ Scenario: Run a scenario
16
+ Given a file named "features/wired.feature" with:
9
17
  """
10
18
  @foo @bar
11
19
  Feature: Wired
@@ -15,15 +23,7 @@ Feature: Wire protocol tags
15
23
  Given we're all wired
16
24
 
17
25
  """
18
- And a file named "features/step_definitions/some_remote_place.wire" with:
19
- """
20
- host: localhost
21
- port: 54321
22
-
23
- """
24
-
25
- Scenario: Run the scenario
26
- Given there is a wire server running on port 54321 which understands the following protocol:
26
+ And there is a wire server running on port 54321 which understands the following protocol:
27
27
  | request | response |
28
28
  | ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
29
29
  | ["begin_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
@@ -45,3 +45,43 @@ Feature: Wire protocol tags
45
45
 
46
46
  """
47
47
 
48
+ Scenario: Run a scenario outline example
49
+ Given a file named "features/wired.feature" with:
50
+ """
51
+ @foo @bar
52
+ Feature: Wired
53
+
54
+ @baz
55
+ Scenario Outline: Everybody's Wired
56
+ Given we're all <something>
57
+
58
+ Examples:
59
+ | something |
60
+ | wired |
61
+
62
+ """
63
+ And there is a wire server running on port 54321 which understands the following protocol:
64
+ | request | response |
65
+ | ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
66
+ | ["begin_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
67
+ | ["invoke",{"id":"1","args":[]}] | ["success"] |
68
+ | ["end_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
69
+ When I run cucumber -f pretty -q
70
+ Then STDERR should be empty
71
+ And it should pass with
72
+ """
73
+ @foo @bar
74
+ Feature: Wired
75
+
76
+ @baz
77
+ Scenario Outline: Everybody's Wired
78
+ Given we're all <something>
79
+
80
+ Examples:
81
+ | something |
82
+ | wired |
83
+
84
+ 1 scenario (1 passed)
85
+ 1 step (1 passed)
86
+
87
+ """
@@ -1,7 +1,9 @@
1
1
  # encoding: utf-8
2
+ desc 'List contributors'
2
3
  task :contributors do
3
- contributors = `git log --pretty=short --no-merges | git shortlog -ne | egrep -ve '^ +' | egrep -ve '^$'`
4
- puts contributors.split("\n").length
4
+ contributors = `git log --pretty=short --no-merges | git shortlog -ne | egrep -ve '^ +' | egrep -ve '^$'`.split("\n")
5
+ puts contributors
6
+ puts "Total: #{contributors.length}"
5
7
  end
6
8
 
7
9
  task :codeswarm do
@@ -0,0 +1,6 @@
1
+ require 'autotest/cucumber_mixin'
2
+ require 'autotest/rails_rspec2'
3
+
4
+ class Autotest::CucumberRailsRspec2 < Autotest::RailsRspec2
5
+ include CucumberMixin
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'autotest/cucumber_mixin'
2
+ require 'autotest/rspec2'
3
+
4
+ class Autotest::CucumberRspec2 < Autotest::Rspec2
5
+ include CucumberMixin
6
+ end
@@ -23,6 +23,10 @@ module Cucumber
23
23
  def accept_hook?(hook)
24
24
  @scenario_outline.accept_hook?(hook)
25
25
  end
26
+
27
+ def source_tag_names
28
+ @scenario_outline.source_tag_names
29
+ end
26
30
 
27
31
  def skip_invoke!
28
32
  example_rows.each do |cells|
@@ -61,6 +65,10 @@ module Cucumber
61
65
  super
62
66
  @scenario_exception = nil
63
67
  end
68
+
69
+ def source_tag_names
70
+ @table.source_tag_names
71
+ end
64
72
 
65
73
  def create_step_invocations!(scenario_outline)
66
74
  @scenario_outline = scenario_outline
@@ -29,7 +29,11 @@ module Cucumber
29
29
  end
30
30
 
31
31
  def to_s
32
- @string.indent(-@quotes_indent)
32
+ # Assume all whitespace before the first triple quote is the same.
33
+ # Also assume the contents of the pystring is indented with the same prefix.
34
+ # This allows indentation with both " " and "\t" characters.
35
+ return @string if @quotes_indent == ""
36
+ @string.gsub(/^#{@quotes_indent[0..0]}{0,#{@quotes_indent.length}}/, "")
33
37
  end
34
38
 
35
39
  def accept(visitor)
@@ -142,11 +142,11 @@ module Cucumber
142
142
  end
143
143
 
144
144
  def actual_keyword
145
- repeat_keywords = [language.but_keywords(false), language.and_keywords(false)].flatten
145
+ repeat_keywords = [language.but_keywords(false), language.and_keywords(false)].flatten.uniq.reject{|kw| kw == '*'}
146
146
  if repeat_keywords.index(@step.keyword) && previous
147
147
  previous.actual_keyword
148
148
  else
149
- keyword
149
+ keyword == '*' ? language.given_keyword : keyword
150
150
  end
151
151
  end
152
152
 
@@ -352,6 +352,7 @@ module Cucumber
352
352
  end
353
353
  @options[:source] &= other_options[:source]
354
354
  @options[:snippets] &= other_options[:snippets]
355
+ @options[:strict] |= other_options[:strict]
355
356
 
356
357
  @profiles += other_options.profiles
357
358
  @expanded_args += other_options.expanded_args
@@ -22,8 +22,14 @@ Defined profiles in cucumber.yml:
22
22
  case(args_from_yml)
23
23
  when String
24
24
  raise YmlLoadError, "The '#{profile}' profile in cucumber.yml was blank. Please define the command line arguments for the '#{profile}' profile in cucumber.yml.\n" if args_from_yml =~ /^\s*$/
25
- require 'shellwords'
26
- args_from_yml = Shellwords.shellwords(args_from_yml)
25
+ if(Cucumber::WINDOWS)
26
+ #Shellwords treats backslash as an escape character so here's a rudimentary approximation of the same code
27
+ args_from_yml = args_from_yml.split
28
+ args_from_yml = args_from_yml.collect {|x| x.gsub(/^\"(.*)\"/,'\1') }
29
+ else
30
+ require 'shellwords'
31
+ args_from_yml = Shellwords.shellwords(args_from_yml)
32
+ end
27
33
  when Array
28
34
  raise YmlLoadError, "The '#{profile}' profile in cucumber.yml was empty. Please define the command line arguments for the '#{profile}' profile in cucumber.yml.\n" if args_from_yml.empty?
29
35
  else
@@ -39,9 +39,9 @@ module Cucumber
39
39
  @coder = HTMLEntities.new
40
40
 
41
41
  if(options[:dry_run])
42
- @status_colors = { :passed => BLACK, :skipped => BLACK, :undefined => BLACK, :failed => BLACK}
42
+ @status_colors = { :passed => BLACK, :skipped => BLACK, :undefined => BLACK, :failed => BLACK, :announced => GREY}
43
43
  else
44
- @status_colors = { :passed => '055902', :skipped => GREY, :undefined => 'F27405', :failed => '730202'}
44
+ @status_colors = { :passed => '055902', :skipped => GREY, :undefined => 'F27405', :failed => '730202', :announced => GREY}
45
45
  end
46
46
 
47
47
  @pdf = Prawn::Document.new
@@ -82,6 +82,13 @@ module Cucumber
82
82
  end
83
83
  end
84
84
 
85
+ def announce(announcement)
86
+ @pdf.fill_color(@status_colors[:announced])
87
+ @pdf.text announcement, :size => 10
88
+ @pdf.fill_color BLACK
89
+ end
90
+
91
+
85
92
  def after_features(features)
86
93
  @pdf.render_file(@file.path)
87
94
  puts "\ndone"
@@ -19,15 +19,33 @@ module Cucumber
19
19
  print_summary(features)
20
20
  end
21
21
 
22
+ def before_feature_element(*args)
23
+ @exception_raised = false
24
+ end
25
+
26
+ def after_feature_element(*args)
27
+ progress(:failed) if @exception_raised
28
+ @exception_raised = false
29
+ end
30
+
31
+ def before_steps(*args)
32
+ progress(:failed) if @exception_raised
33
+ @exception_raised = false
34
+ end
35
+
36
+ def after_steps(*args)
37
+ @exception_raised = false
38
+ end
39
+
22
40
  def after_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background)
23
41
  progress(status)
24
42
  @status = status
25
43
  end
26
-
44
+
27
45
  def before_outline_table(outline_table)
28
46
  @outline_table = outline_table
29
47
  end
30
-
48
+
31
49
  def after_outline_table(outline_table)
32
50
  @outline_table = nil
33
51
  end
@@ -38,6 +56,10 @@ module Cucumber
38
56
  progress(status) unless table_header_cell?(status)
39
57
  end
40
58
 
59
+ def exception(*args)
60
+ @exception_raised = true
61
+ end
62
+
41
63
  private
42
64
 
43
65
  def print_summary(features)
@@ -7,6 +7,17 @@ $KCODE='u' unless Cucumber::RUBY_1_9
7
7
  if Cucumber::WINDOWS
8
8
  require 'iconv'
9
9
 
10
+ if ENV['CUCUMBER_OUTPUT_ENCODING']
11
+ Cucumber::CODEPAGE = ENV['CUCUMBER_OUTPUT_ENCODING']
12
+ elsif Cucumber::WINDOWS_MRI
13
+ Cucumber::CODEPAGE = "cp#{Win32::Console::OutputCP()}"
14
+ elsif `cmd /c chcp` =~ /(\d+)/
15
+ Cucumber::CODEPAGE = "cp#{$1.to_i}"
16
+ else
17
+ Cucumber::CODEPAGE = "cp1252"
18
+ STDERR.puts("WARNING: Couldn't detect your output codepage. Assuming it is 1252. You may have to chcp 1252 or SET CUCUMBER_OUTPUT_ENCODING=cp1252.")
19
+ end
20
+
10
21
  module Cucumber
11
22
  module WindowsOutput #:nodoc:
12
23
  def self.extended(o)
@@ -44,15 +55,4 @@ if Cucumber::WINDOWS
44
55
  STDERR.extend(self)
45
56
  end
46
57
  end
47
-
48
- if ENV['CUCUMBER_OUTPUT_ENCODING']
49
- Cucumber::CODEPAGE = ENV['CUCUMBER_OUTPUT_ENCODING']
50
- elsif Cucumber::WINDOWS_MRI
51
- Cucumber::CODEPAGE = "cp#{Win32::Console::OutputCP()}"
52
- elsif `cmd /c chcp` =~ /(\d+)/
53
- Cucumber::CODEPAGE = "cp#{$1.to_i}"
54
- else
55
- Cucumber::CODEPAGE = "cp1252"
56
- STDERR.cucumber_puts("WARNING: Couldn't detect your output codepage. Assuming it is 1252. You may have to chcp 1252 or SET CUCUMBER_OUTPUT_ENCODING=cp1252.")
57
- end
58
58
  end
@@ -1,11 +1,16 @@
1
1
  # encoding: UTF-8
2
- # We use the codes here (prefer 2 letters when possible)
3
- # http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
2
+ #
3
+ # We use ISO 639-1 (language) and ISO 3166 alpha-2 (region - if appliccable):
4
+ # http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
5
+ # http://en.wikipedia.org/wiki/ISO_3166-1
4
6
  #
5
7
  # If you want several aliases for a keyword, just separate them
6
8
  # with a | character. Make sure there are no ambiguities in the
7
9
  # keywords.
8
10
  #
11
+ # If you do *not* want a trailing space after a keyword, end it with a < character.
12
+ # (See Chinese for examples).
13
+ #
9
14
  "en":
10
15
  name: English
11
16
  native: English
@@ -20,10 +25,6 @@
20
25
  and: "*|And"
21
26
  but: "*|But"
22
27
 
23
- # Please help us keeping the languages below uptodate. The parsers for a language
24
- # that is missing a keyword will expect the English word until the missing word(s)
25
- # are added.
26
- #
27
28
  # Please keep the grammars in alphabetical order by name from here and down.
28
29
 
29
30
  "ar":
@@ -52,7 +53,7 @@
52
53
  then: "*|То"
53
54
  and: "*|И"
54
55
  but: "*|Но"
55
- "cat":
56
+ "ca":
56
57
  name: Catalan
57
58
  native: català
58
59
  background: Rerefons|Antecedents
@@ -65,7 +66,7 @@
65
66
  then: "*|Aleshores|Cal"
66
67
  and: "*|I"
67
68
  but: "*|Però"
68
- "cy":
69
+ "cy-GB":
69
70
  name: Welsh
70
71
  native: Cymraeg
71
72
  background: Cefndir
@@ -390,7 +391,7 @@
390
391
  then: "*|Atunci"
391
392
  and: "*|Si"
392
393
  but: "*|Dar"
393
- "ro2":
394
+ "ro-RO":
394
395
  name: Romanian (diacritical)
395
396
  native: română (diacritical)
396
397
  background: Condiţii
@@ -416,7 +417,7 @@
416
417
  then: "*|То"
417
418
  and: "*|И|К тому же"
418
419
  but: "*|Но|А"
419
- "se":
420
+ "sv":
420
421
  name: Swedish
421
422
  native: Svenska
422
423
  feature: Egenskap
@@ -443,8 +444,8 @@
443
444
  and: "*|A"
444
445
  but: "*|Ale"
445
446
  "sr-Latn":
446
- name: Serbian_latin
447
- native: Srpski_latinica
447
+ name: Serbian (Latin)
448
+ native: Srpski (Latinica)
448
449
  feature: Funkcionalnost|Mogućnost|Mogucnost|Osobina
449
450
  background: Kontekst|Osnova|Pozadina
450
451
  scenario: Scenario|Primer
@@ -455,7 +456,7 @@
455
456
  then: "*|Onda"
456
457
  and: "*|I"
457
458
  but: "*|Ali"
458
- "sr":
459
+ "sr-Cyrl":
459
460
  name: Serbian
460
461
  native: Српски
461
462
  feature: Функционалност|Могућност|Особина
@@ -1542,263 +1542,6 @@ module Cucumber
1542
1542
  r0
1543
1543
  end
1544
1544
 
1545
- module PyString0
1546
- end
1547
-
1548
- module PyString1
1549
- def open_py_string
1550
- elements[0]
1551
- end
1552
-
1553
- def s
1554
- elements[1]
1555
- end
1556
-
1557
- def close_py_string
1558
- elements[2]
1559
- end
1560
- end
1561
-
1562
- module PyString2
1563
- def at_line?(line)
1564
- line >= open_py_string.line && line <= close_py_string.line
1565
- end
1566
-
1567
- def build
1568
- Ast::PyString.new(open_py_string.line, close_py_string.line, s.text_value, open_py_string.indentation)
1569
- end
1570
- end
1571
-
1572
- def _nt_py_string
1573
- start_index = index
1574
- if node_cache[:py_string].has_key?(index)
1575
- cached = node_cache[:py_string][index]
1576
- if cached
1577
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1578
- @index = cached.interval.end
1579
- end
1580
- return cached
1581
- end
1582
-
1583
- i0, s0 = index, []
1584
- r1 = _nt_open_py_string
1585
- s0 << r1
1586
- if r1
1587
- s2, i2 = [], index
1588
- loop do
1589
- i3, s3 = index, []
1590
- i4 = index
1591
- r5 = _nt_close_py_string
1592
- if r5
1593
- r4 = nil
1594
- else
1595
- @index = i4
1596
- r4 = instantiate_node(SyntaxNode,input, index...index)
1597
- end
1598
- s3 << r4
1599
- if r4
1600
- if index < input_length
1601
- r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
1602
- @index += 1
1603
- else
1604
- terminal_parse_failure("any character")
1605
- r6 = nil
1606
- end
1607
- s3 << r6
1608
- end
1609
- if s3.last
1610
- r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
1611
- r3.extend(PyString0)
1612
- else
1613
- @index = i3
1614
- r3 = nil
1615
- end
1616
- if r3
1617
- s2 << r3
1618
- else
1619
- break
1620
- end
1621
- end
1622
- r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
1623
- s0 << r2
1624
- if r2
1625
- r7 = _nt_close_py_string
1626
- s0 << r7
1627
- end
1628
- end
1629
- if s0.last
1630
- r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1631
- r0.extend(PyString1)
1632
- r0.extend(PyString2)
1633
- else
1634
- @index = i0
1635
- r0 = nil
1636
- end
1637
-
1638
- node_cache[:py_string][start_index] = r0
1639
-
1640
- r0
1641
- end
1642
-
1643
- module OpenPyString0
1644
- def indent
1645
- elements[0]
1646
- end
1647
-
1648
- def eol
1649
- elements[3]
1650
- end
1651
- end
1652
-
1653
- module OpenPyString1
1654
- def indentation
1655
- indent.text_value.length
1656
- end
1657
-
1658
- def line
1659
- indent.line
1660
- end
1661
- end
1662
-
1663
- def _nt_open_py_string
1664
- start_index = index
1665
- if node_cache[:open_py_string].has_key?(index)
1666
- cached = node_cache[:open_py_string][index]
1667
- if cached
1668
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1669
- @index = cached.interval.end
1670
- end
1671
- return cached
1672
- end
1673
-
1674
- i0, s0 = index, []
1675
- s1, i1 = [], index
1676
- loop do
1677
- r2 = _nt_space
1678
- if r2
1679
- s1 << r2
1680
- else
1681
- break
1682
- end
1683
- end
1684
- r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
1685
- s0 << r1
1686
- if r1
1687
- if has_terminal?('"""', false, index)
1688
- r3 = instantiate_node(SyntaxNode,input, index...(index + 3))
1689
- @index += 3
1690
- else
1691
- terminal_parse_failure('"""')
1692
- r3 = nil
1693
- end
1694
- s0 << r3
1695
- if r3
1696
- s4, i4 = [], index
1697
- loop do
1698
- r5 = _nt_space
1699
- if r5
1700
- s4 << r5
1701
- else
1702
- break
1703
- end
1704
- end
1705
- r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
1706
- s0 << r4
1707
- if r4
1708
- r6 = _nt_eol
1709
- s0 << r6
1710
- end
1711
- end
1712
- end
1713
- if s0.last
1714
- r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1715
- r0.extend(OpenPyString0)
1716
- r0.extend(OpenPyString1)
1717
- else
1718
- @index = i0
1719
- r0 = nil
1720
- end
1721
-
1722
- node_cache[:open_py_string][start_index] = r0
1723
-
1724
- r0
1725
- end
1726
-
1727
- module ClosePyString0
1728
- def eol
1729
- elements[0]
1730
- end
1731
-
1732
- def quotes
1733
- elements[2]
1734
- end
1735
-
1736
- def white
1737
- elements[3]
1738
- end
1739
- end
1740
-
1741
- module ClosePyString1
1742
- def line
1743
- quotes.line
1744
- end
1745
- end
1746
-
1747
- def _nt_close_py_string
1748
- start_index = index
1749
- if node_cache[:close_py_string].has_key?(index)
1750
- cached = node_cache[:close_py_string][index]
1751
- if cached
1752
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1753
- @index = cached.interval.end
1754
- end
1755
- return cached
1756
- end
1757
-
1758
- i0, s0 = index, []
1759
- r1 = _nt_eol
1760
- s0 << r1
1761
- if r1
1762
- s2, i2 = [], index
1763
- loop do
1764
- r3 = _nt_space
1765
- if r3
1766
- s2 << r3
1767
- else
1768
- break
1769
- end
1770
- end
1771
- r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
1772
- s0 << r2
1773
- if r2
1774
- if has_terminal?('"""', false, index)
1775
- r4 = instantiate_node(SyntaxNode,input, index...(index + 3))
1776
- @index += 3
1777
- else
1778
- terminal_parse_failure('"""')
1779
- r4 = nil
1780
- end
1781
- s0 << r4
1782
- if r4
1783
- r5 = _nt_white
1784
- s0 << r5
1785
- end
1786
- end
1787
- end
1788
- if s0.last
1789
- r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
1790
- r0.extend(ClosePyString0)
1791
- r0.extend(ClosePyString1)
1792
- else
1793
- @index = i0
1794
- r0 = nil
1795
- end
1796
-
1797
- node_cache[:close_py_string][start_index] = r0
1798
-
1799
- r0
1800
- end
1801
-
1802
1545
  def _nt_white
1803
1546
  start_index = index
1804
1547
  if node_cache[:white].has_key?(index)