macros4cuke 0.2.18 → 0.2.19

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.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.2.19 / 2013-05-06
2
+ * [CHANGE] Added validation of macro argument names in new `Engine::parse_tag` method.
3
+ * [CHANGE] InvalidCharError exception added.
4
+ * [CHANGE] File `engine_spec.rb`: Added one RSpec example for an invalid argument name.
5
+ * [CHANGE] File `README.md`: added a new section on naming macro arguments.
6
+
1
7
  ## 0.2.18 / 2013-05-06
2
8
  * [CHANGE] Amended spec files and added a new demo feature. SimpleCov code coverage raised to more than 97%.
3
9
  * [CHANGE] Macro-step arguments can be multivalued (experimental)
data/README.md CHANGED
@@ -245,6 +245,14 @@ Here are few observations worth noticing:
245
245
  the value "Main Street, 22".
246
246
  - Data rows don't have to follow strictly the order of the arguments in the sub-step sequence.
247
247
 
248
+ ## Naming macro-step arguments ##
249
+ In line with most computer languages, Macros4Cuke accepts argument names containing alphanumeric characters and
250
+ underscores.
251
+ In fact, the only characters that are not allowed in argument names are the following punctuation or delimiting
252
+ signs:
253
+ __\!"'\#$%\&\*\+\-/,\.\:\;\=\?\(\)\<\>\[\]\{\}\\\^\`\|\~__
254
+
255
+
248
256
  ## With great power comes great responsibility. ##
249
257
  _Stan Lee_
250
258
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Macros4Cuke # Module used as a namespace
5
5
  # The version number of the gem.
6
- Version = '0.2.18'
6
+ Version = '0.2.19'
7
7
 
8
8
  # Brief description of the gem.
9
9
  Description = "Macros for Cucumber"
@@ -1,4 +1,4 @@
1
- # encoding: utf-8 -- You should see a paragraph character: §
1
+ # encoding: utf-8 -- You should see a paragraph character: §
2
2
  # File: exceptions.rb
3
3
 
4
4
  module Macros4Cuke # Module used as a namespace
@@ -8,7 +8,7 @@ module Macros4Cuke # Module used as a namespace
8
8
  class Macros4CukeError < StandardError
9
9
  end # class
10
10
 
11
- # Raised when one attempts to define a new macro
11
+ # Raised when one attempts to define a new macro
12
12
  # that has the same phrase as an existing macro.
13
13
  class DuplicateMacroError < Macros4CukeError
14
14
  def initialize(aPhrase)
@@ -44,7 +44,15 @@ class EmptyArgumentError < Macros4CukeError
44
44
  end # class
45
45
 
46
46
 
47
- # Raised when one invokes a macro-step with an unknown phrase.
47
+ # Raised when an argument name contains invalid characters.
48
+ class InvalidCharError < Macros4CukeError
49
+ def initialize(aText, aWrongChar)
50
+ super("The invalid sign '#{aWrongChar}' occurs in the argument/tag '#{aText}'.")
51
+ end
52
+ end # class
53
+
54
+
55
+ # Raised when one invokes a macro-step with an unknown phrase.
48
56
  class UnknownMacroError < Macros4CukeError
49
57
  def initialize(aPhrase)
50
58
  super("Unknown macro-step with phrase: '#{aPhrase}'.")
@@ -54,7 +62,7 @@ end # class
54
62
 
55
63
 
56
64
  # Raised when one invokes a macro-step with an argument
57
- # that has an unknown name.
65
+ # that has an unknown name.
58
66
  class UnknownArgumentError < Macros4CukeError
59
67
  def initialize(argName)
60
68
  super("Unknown macro-step argument '#{argName}'.")
@@ -101,6 +101,15 @@ end # class
101
101
  # while Mustache use !{{...}} delimiters),
102
102
  # - Feature files are meant to be simple, so should the template engine be.
103
103
  class Engine
104
+ # The regular expression that matches any punctuation sign or delimiter that is forbidden between chevrons <...> template tags.
105
+ DisallowedSigns = begin
106
+ forbidden = '!"#' + "$%&'()*+,-./:;<=>?[\\]^`{|}~" # Used concatenation (+) to work around Ruby bug!
107
+ all_escaped = []
108
+ forbidden.each_char() { |ch| all_escaped << Regexp.escape(ch) }
109
+ pattern = all_escaped.join("|")
110
+ Regexp.new(pattern)
111
+ end
112
+
104
113
  # The original text of the template is kept here.
105
114
  attr_reader(:source)
106
115
 
@@ -140,7 +149,6 @@ public
140
149
  return @variables
141
150
  end
142
151
 
143
-
144
152
  # Class method. Parse the given line text into a raw representation.
145
153
  # @return [Array] Couples of the form:
146
154
  # [:static, text] or [:dynamic, tag text]
@@ -211,7 +219,7 @@ private
211
219
  end
212
220
 
213
221
 
214
- # [aCouple] a two-element array of the form: [kind, text]
222
+ # @param aCouple [Array] a two-element array of the form: [kind, text]
215
223
  # Where kind must be one of :static, :dynamic
216
224
  def compile_couple(aCouple)
217
225
  (kind, text) = aCouple
@@ -221,14 +229,24 @@ private
221
229
  StaticText.new(text)
222
230
 
223
231
  when :dynamic
224
- Placeholder.new(text)
232
+ parse_tag(text)
225
233
  else
226
234
  raise StandardError, "Internal error: Don't know template element of kind #{kind}"
227
235
  end
228
-
236
+
229
237
  return result
230
238
  end
231
239
 
240
+ # Parse the contents of a tag entry.
241
+ # @param aText [String] The text that is enclosed between chevrons.
242
+ def parse_tag(aText)
243
+ # Disallow punctuation and delimiter signs in tags.
244
+ matching = DisallowedSigns.match(aText)
245
+ raise InvalidCharError.new(aText, matching[0]) if matching
246
+
247
+ return Placeholder.new(aText)
248
+ end
249
+
232
250
  end # class
233
251
 
234
252
  end # module
@@ -4,6 +4,7 @@
4
4
  require_relative '../../spec_helper'
5
5
  require_relative '../../../lib/macros4cuke/templating/engine' # Load the class under test
6
6
 
7
+
7
8
  module Macros4Cuke
8
9
 
9
10
  module Templating # Open this namespace to get rid of module qualifier prefixes
@@ -171,9 +172,14 @@ SNIPPET
171
172
  text_w_empty_arg = sample_template.sub(/userid/, '')
172
173
  error_message = %Q|An empty or blank argument occurred in 'And I fill in "Username" with "<>"'.|
173
174
  lambda { Engine.new text_w_empty_arg }.should raise_error(Macros4Cuke::EmptyArgumentError, error_message)
175
+ end
174
176
 
177
+ it "should complain when a placeholder contains an invalid character" do
178
+ text_w_empty_arg = sample_template.sub(/userid/, 'user%id')
179
+ error_message = "The invalid sign '%' occurs in the argument/tag 'user%id'."
180
+ lambda { Engine.new text_w_empty_arg }.should raise_error(Macros4Cuke::InvalidCharError, error_message)
175
181
  end
176
- end
182
+ end # context
177
183
 
178
184
  context "Provided services" do
179
185
 
@@ -208,7 +214,7 @@ SNIPPET
208
214
  SNIPPET
209
215
 
210
216
  rendered_text.should == expected
211
-
217
+
212
218
  # Case of an actual that's not a String
213
219
  locals = {'userid' => "johndoe", "password" => 12345678 }
214
220
  rendered_text = subject.render(Object.new, locals)
@@ -220,8 +226,8 @@ SNIPPET
220
226
  And I click "Sign in"
221
227
  SNIPPET
222
228
 
223
- rendered_text.should == expected
224
-
229
+ rendered_text.should == expected
230
+
225
231
 
226
232
  # Place actual value in context object
227
233
  Context = Struct.new(:userid, :password)
@@ -236,7 +242,7 @@ SNIPPET
236
242
  SNIPPET
237
243
 
238
244
  rendered_text.should == expected
239
-
245
+
240
246
 
241
247
  # Case of an empty source template text
242
248
  instance = Engine.new ''
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: macros4cuke
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.18
4
+ version: 0.2.19
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-06 00:00:00.000000000 Z
12
+ date: 2013-05-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cucumber