I''ve got a small function that I''m developing (maybe you''ll recognize it): code: sprintf: function(replacement) { var escapedString = this.replace(/\\/g, ''\\\\''); var values = $A(arguments); Template.SprintfPattern = /(^|.|\r|\n)(@\(s\)(.*?))/; var sprintfTemplate = new Template(escapedString, Template.SprintfPattern); return sprintfTemplate.evaluate(values); } unit test: testStrinSprintf: function() { with(this) { assertEqual(''mary had a litte lamb'', ''@s had a @s @s''.sprintf([''mary'',''little'',''lamb''])); }}, However, it is not returning the expected value. It is only returning the original string. Any help with this would be greatly appreciated! Thanks, Ian --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Christophe Porteneuve
2006-Nov-03 09:42 UTC
Re: pattern help for custom template - strings
Hey Ian, OK, you''re not using Template for what it''s designed to do. Template is a class that plucks properties out of an object, using a custom syntax to identify property names amidst the pattern text. It is NOT intended for stuff such as "%s" or "@s", where "s" would mean "string" instead of "property s". You can simulate this, but in a very shallow manner, by using only numerical indices, without conversion characters, and passing an array as argument to the evaluate function. Since the array has a numerically-named property for each cell, you''re good to go. But that won''t take you further. Besides, \-escaping seems unnecessary for your needs. your detection pattern is incorrect: Ian Tyndall a écrit :> Template.SprintfPattern = /(^|.|\r|\n)(@\(s\)(.*?))/;First, you don''t *need* to pollute the Template object with a custom pattern property (which is specific to your needs, not global). Store it as a constant in your own object instead (String, here), in order to avoid recomputing the regex on each call. Second, a Template detection pattern must isolate *3 groups*: 1. The character/boundary immediately before the special sequence 2. The delimiter(s) of the special sequence (defaults to #{...}) 3. The property name inside the special sequence (usually uses (.*?), which is a reluctantly-quantified generic grab). Your regex doesn''t do that at all. The beginning is alright: 1. (^|.|\r|\n) This is virtually constant (there''s never a reason to change it, AFAIK). The second part ic clearly wrong though, as your second group is: 2. (@\(s\)(.*?)) Which basically says that your special sequences start by "@(s)", and have no end delimiter. It also provides the third group: 3. (.*?) Which is correct, but misplaced. To actually get this to work on your example, you''d have to go like this: "@s0 had a @s1 @s2".sprintf(''mary'', ''little'', ''lamb''); Note that I *do not* bracket the arguments in an array: there are three arguments here. Since your method wraps them in an array already, using $A, that''s enough (and that''s more convenient for the calling code). If you use a manual array bracketing, you''ll end up with a single argument. Also note that the "s" part in your detection pattern becomes irrelevant, since you can''t apply conversion on the go. You could as well get rid of it. Here''s a simpler version: Object.extend(String.prototype, { SPRINTF_PATTERN: /(^|.|\r|\n)(@(\d+))/, sprintf: function() { var obj = $A(arguments); return new Template(this, this.SPRINTF_PATTERN).evaluate(obj); } }); As for the unit test: testStrinSprintf: function() { with(this) { assertEqual(''mary had a litte lamb'', ''@0 had a @1 @2''.sprintf(''mary'',''little'',''lamb'')); }}, Just remember that you WON''T be able to emulate sprintf behavior (insofar as formatting and converting is concerned) using Template. The mechanism is only intended at property injection in a patterned text. ''HTH -- Christophe Porteneuve aka TDD tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Christophe Porteneuve wrote:>Hey Ian, > >OK, you''re not using Template for what it''s designed to do. Template is >a class that plucks properties out of an object, using a custom syntax >to identify property names amidst the pattern text. > >It is NOT intended for stuff such as "%s" or "@s", where "s" would mean >"string" instead of "property s". > >You can simulate this, but in a very shallow manner, by using only >numerical indices, without conversion characters, and passing an array >as argument to the evaluate function. Since the array has a >numerically-named property for each cell, you''re good to go. But that >won''t take you further. > >Besides, \-escaping seems unnecessary for your needs. your detection >pattern is incorrect: > >Ian Tyndall a écrit : > > >>Template.SprintfPattern = /(^|.|\r|\n)(@\(s\)(.*?))/; >> >> > >First, you don''t *need* to pollute the Template object with a custom >pattern property (which is specific to your needs, not global). Store >it as a constant in your own object instead (String, here), in order to >avoid recomputing the regex on each call. > >Second, a Template detection pattern must isolate *3 groups*: > > 1. The character/boundary immediately before the special sequence > 2. The delimiter(s) of the special sequence (defaults to #{...}) > 3. The property name inside the special sequence (usually uses > (.*?), which is a reluctantly-quantified generic grab). > >Your regex doesn''t do that at all. The beginning is alright: > > 1. (^|.|\r|\n) > >This is virtually constant (there''s never a reason to change it, AFAIK). > The second part ic clearly wrong though, as your second group is: > > 2. (@\(s\)(.*?)) > >Which basically says that your special sequences start by "@(s)", and >have no end delimiter. It also provides the third group: > > 3. (.*?) > >Which is correct, but misplaced. To actually get this to work on your >example, you''d have to go like this: > > "@s0 had a @s1 @s2".sprintf(''mary'', ''little'', ''lamb''); > >Note that I *do not* bracket the arguments in an array: there are three >arguments here. Since your method wraps them in an array already, using >$A, that''s enough (and that''s more convenient for the calling code). If >you use a manual array bracketing, you''ll end up with a single argument. > >Also note that the "s" part in your detection pattern becomes >irrelevant, since you can''t apply conversion on the go. You could as >well get rid of it. Here''s a simpler version: > >Object.extend(String.prototype, { > SPRINTF_PATTERN: /(^|.|\r|\n)(@(\d+))/, > sprintf: function() { > var obj = $A(arguments); > return new Template(this, this.SPRINTF_PATTERN).evaluate(obj); > } >}); > >As for the unit test: > > testStrinSprintf: function() { with(this) { > assertEqual(''mary had a litte lamb'', > ''@0 had a @1 @2''.sprintf(''mary'',''little'',''lamb'')); > }}, > >Just remember that you WON''T be able to emulate sprintf behavior >(insofar as formatting and converting is concerned) using Template. The >mechanism is only intended at property injection in a patterned text. > >''HTH > > >Thanks for the great help and explanation! --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---