Hi all, I''m currently doing a little CMS system in Rails and I would like the user/administrator of a site to be able to render partials on pages. I have a Page model with a content attribute. Inside that attribute I would like the admin to be able to put something like this: {contact_form submit:"Submit now!" reset:"Reset form"} This is just an example, but this should then render a partial like this: render :partial => "widgets/contact_form", :locals => {:submit => "Submit now!", :reset => "Reset form"} I have been trying to make up a regular expression to approach this, but I''m not very good at it. It looks like this: /\{(\w+) (\w+):(.+)*\}/ But it is hard to make it respect multiple arguments, if you know what I mean. Now, if any of you have an idea of how to finish this regular expression, or maybe know a different solution of how to let the admin render partials "dynamically", I would appreciate if you''d let me know. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I''d have a look a string scanner if I were you Fred Sent from my iPhone On 8 Oct 2008, at 18:12, David Trasbo <rails-mailing-list@andreas- s.net> wrote:> > Hi all, > > I''m currently doing a little CMS system in Rails and I would like the > user/administrator of a site to be able to render partials on pages. I > have a Page model with a content attribute. Inside that attribute I > would like the admin to be able to put something like this: > > {contact_form submit:"Submit now!" reset:"Reset form"} > > This is just an example, but this should then render a partial like > this: > > render :partial => "widgets/contact_form", :locals => {:submit => > "Submit now!", :reset => "Reset form"} > > I have been trying to make up a regular expression to approach this, > but > I''m not very good at it. It looks like this: > > /\{(\w+) (\w+):(.+)*\}/ > > But it is hard to make it respect multiple arguments, if you know > what I > mean. Now, if any of you have an idea of how to finish this regular > expression, or maybe know a different solution of how to let the admin > render partials "dynamically", I would appreciate if you''d let me > know. > -- > Posted via http://www.ruby-forum.com/. > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:> I''d have a look a string scanner if I were you > Fred > > Sent from my iPhoneThat''s exactly what I''ve been thinking of, but the real challenge is to get the regular expression right. It needs to respect multiple arguments. Any suggestions? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 8 Oct 2008, at 19:00, David Trasbo wrote:> > Frederick Cheung wrote: > >> I''d have a look a string scanner if I were you >> Fred >> >> Sent from my iPhone > > That''s exactly what I''ve been thinking of, but the real challenge is > to > get the regular expression right. It needs to respect multiple > arguments. Any suggestions?that''s the point - with stringscanner you don''t need to come up with one giant regular expression that gets everything right as a quick example, this require ''strscan'' s = StringScanner.new(''blah {some_partial arg1:foo arg2:bar} other stuff here {otherpartial arg1:baz}'') while s.scan_until /\{/ puts "start of call" puts s.scan /\w+/ s.skip /\s+/ while output=s.scan( /\w+:\w+/) puts output s.skip /\s+/ end s.skip_until /\}/ puts "end of call" end outputs start of call some_partial arg1:foo arg2:bar end of call start of call otherpartial arg1:baz end of call Fred> > -- > Posted via http://www.ruby-forum.com/. > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:>> get the regular expression right. It needs to respect multiple >> arguments. Any suggestions? > > that''s the point - with stringscanner you don''t need to come up with > one giant regular expression that gets everything rightAha! I thought you meant the RegExp#scan method.> as a quick example, this > > require ''strscan'' > s = StringScanner.new(''blah {some_partial arg1:foo arg2:bar} other > stuff here {otherpartial arg1:baz}'') > > while s.scan_until /\{/ > puts "start of call" > puts s.scan /\w+/ > s.skip /\s+/ > while output=s.scan( /\w+:\w+/) > puts output > s.skip /\s+/ > end > s.skip_until /\}/ > puts "end of call" > end > > outputs > > start of call > some_partial > arg1:foo > arg2:bar > end of call > start of call > otherpartial > arg1:baz > end of callThis looks just great! I''ll return when I''ve written a complete method. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
David Trasbo wrote:>> as a quick example, this >> >> require ''strscan'' >> s = StringScanner.new(''blah {some_partial arg1:foo arg2:bar} other >> stuff here {otherpartial arg1:baz}'') >> >> while s.scan_until /\{/ >> puts "start of call" >> puts s.scan /\w+/ >> s.skip /\s+/ >> while output=s.scan( /\w+:\w+/) >> puts output >> s.skip /\s+/ >> end >> s.skip_until /\}/ >> puts "end of call" >> end...> This looks just great! I''ll return when I''ve written a complete method.Okay, I''ve been taking a look at this, and I''m facing a problem. When I''ve scanned a string I want to actually replace all the {some_partial foo:bar}''s with partial renderings. I''ve been looking through the StringScanner documentation (http://www.ruby-doc.org/core/classes/StringScanner.html), but it doesn''t seem to cover the topic of replacing matches instead of just extracting it, if you know what I mean. How can I replace a {some_partial foo:bar} match with a partial rendering? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Oct 9, 7:53 am, David Trasbo <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> David Trasbo wrote: > I''ve been looking through the StringScanner documentation > (http://www.ruby-doc.org/core/classes/StringScanner.html), but it > doesn''t seem to cover the topic of replacing matches instead of just > extracting it, if you know what I mean. > > How can I replace a {some_partial foo:bar} match with a partial > rendering?the string scanner will tell you its position. Keep track of the relevant positions and then use String''s usual methods to replace content between 2 positions. Fred> -- > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:>> How can I replace a {some_partial foo:bar} match with a partial >> rendering? > > the string scanner will tell you its position. Keep track of the > relevant positions and then use String''s usual methods to replace > content between 2 positions.Got it. Okay, I have made this method: def dropify(content) # create a StringScanner s = StringScanner.new(content) while s.scan_until /\{/ # where are we now? from = s.pointer - 1 # locals to pass to the partial arguments = {} partial = s.scan /\w+/ s.skip /\s+/ while argument = s.scan( /\w+:\w+/) # splitting the argument up into a name and a value argument.split!(":") name = argument.first.to_sym value = argument.last # putting it into the arguments hash arguments[name] = value s.skip /\s+/ end # where are we now? to = s.pointer+1 s.skip_until /\}/ # put the partial on top of the {some_partial foo:bar} match content[from, to] = render :partial => "drops/#{partial}", :locals => arguments end # return content end Let me start out by saying that both the argument, name, value, arguments, to and from has the values they should have when I debug them, but for some reason I''m getting an error that looks like this: compile error C:/.../app/views/drops/_contact_form.html.erb:-11: syntax error, unexpected tIDENTIFIER, expecting '']'' bar=foos = local_assigns[:bar=foo] ^ C:/.../app/views/drops/_contact_form.html.erb:-7: syntax error, unexpected tASSOC, expecting kEND bar=>foos = local_assigns[:bar=>foo] ^ C:/.../app/views/drops/_contact_form.html.erb:-5: syntax error, unexpected tIDENTIFIER, expecting '']'' foo=bar = local_assigns[:foo=bar] Do anyone know what this means? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Oct 9, 9:39 am, David Trasbo <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> Frederick Cheung wrote: > >> How can I replace a {some_partial foo:bar} match with a partial > >> rendering? > > > the string scanner will tell you its position. Keep track of the > > relevant positions and then use String''s usual methods to replace > > content between 2 positions. > > Got it. Okay, I have made this method: > > def dropify(content) > # create a StringScanner > s = StringScanner.new(content) > while s.scan_until /\{/ > # where are we now? > from = s.pointer - 1 > # locals to pass to the partial > arguments = {} > partial = s.scan /\w+/ > s.skip /\s+/ > while argument = s.scan( /\w+:\w+/) > # splitting the argument up into a name and a value > argument.split!(":") > name = argument.first.to_sym > value = argument.last > # putting it into the arguments hash > arguments[name] = value > s.skip /\s+/ > end > # where are we now? > to = s.pointer+1 > s.skip_until /\}/ > # put the partial on top of the {some_partial foo:bar} match > content[from, to] = render :partial => "drops/#{partial}", :locals > => arguments > end > # return > content > end > > Let me start out by saying that both the argument, name, value, > arguments, to and from has the values they should have when I debug > them, but for some reason I''m getting an error that looks like this:A general point - it may not be advisable to modify the string while stringscanner is iterating over it At least on my version of ruby String#split! doesn''t exist, and the errors suggest it didn''t actually do what you think it did (and I struggle to see how it could exist) name, value = arguments.split(/:/) would probably work better. The error you get later is a reflection of the fact that the keys in your locals are things like bar=foo (and i imagine the values are blank) Fred --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:>> Let me start out by saying that both the argument, name, value, >> arguments, to and from has the values they should have when I debug >> them, but for some reason I''m getting an error that looks like this:> A general point - it may not be advisable to modify the string while > stringscanner is iterating over itI don''t see other possibilities.> At least on my version of ruby String#split! doesn''t exist, and the > errors suggest it didn''t actually do what you think it did (and I > struggle to see how it could exist) > name, value = arguments.split(/:/) would probably work better.I see, that is corrected now.> The error you get later is a reflection of the fact that the keys in > your locals are things like bar=foo (and i imagine the values are > blank)Unfortunately that is not true. When I comment out the "content[from, to] = render..." line and put "puts debug arguments" on the line before so it looks like this: ... s.skip_until /\}/ puts debug arguments #content[from, to] = render :partial => "drops/#{partial}", :locals => arguments ... I get output similar to this: --- foo: bars bar: foos I assume this means that the arguments hash is correctly formatted. But I''m getting the error when the "content[from, to] = render..." line is NOT commented out, anyway. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 9 Oct 2008, at 10:15, David Trasbo wrote:> > Frederick Cheung wrote: > >>> Let me start out by saying that both the argument, name, value, >>> arguments, to and from has the values they should have when I debug >>> them, but for some reason I''m getting an error that looks like this: > >> A general point - it may not be advisable to modify the string while >> stringscanner is iterating over it > > I don''t see other possibilities.accumulate the replacements you need and do them at the end (last one first)> > >> At least on my version of ruby String#split! doesn''t exist, and the >> errors suggest it didn''t actually do what you think it did (and I >> struggle to see how it could exist) >> name, value = arguments.split(/:/) would probably work better. > > I see, that is corrected now. > >> The error you get later is a reflection of the fact that the keys in >> your locals are things like bar=foo (and i imagine the values are >> blank) > > Unfortunately that is not true. When I comment out the "content[from, > to] = render..." line and put "puts debug arguments" on the line > before > so it looks like this: >given how :locals is handled it seems highly likely> ... > s.skip_until /\}/ > puts debug arguments > #content[from, to] = render :partial => "drops/#{partial}", :locals => > arguments > ... > > I get output similar to this: > > --- > foo: bars > bar: foos >It would be a lot simpler to just stick a breakpoint in there (or output arguments.inspect)> I assume this means that the arguments hash is correctly formatted. > But > I''m getting the error when the "content[from, to] = render..." line is > NOT commented out, anyway. > -- > Posted via http://www.ruby-forum.com/. > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:> On 9 Oct 2008, at 10:15, David Trasbo wrote: > >> I don''t see other possibilities. > accumulate the replacements you need and do them at the end (last one > first) >>> your locals are things like bar=foo (and i imagine the values are >>> blank) >> >> Unfortunately that is not true. When I comment out the "content[from, >> to] = render..." line and put "puts debug arguments" on the line >> before >> so it looks like this: >> > given how :locals is handled it seems highly likely >> foo: bars >> bar: foos >> > It would be a lot simpler to just stick a breakpoint in there (or > output arguments.inspect)I''m quite close to the solution now, my method now looks like this: def dropify(content) s = StringScanner.new(content) drops = {} i = 0 while s.scan_until /\{/ drop = {} drop[:from] = s.pointer - 1 drop[:arguments] = {} drop[:partial] = s.scan /\w+/ s.skip /\s+/ while argument = s.scan( /\w+:\w+/) name, value = argument.split(/:/) drop[:arguments][name.to_sym] = value s.skip /\s+/ end drop[:to] = s.pointer+1 s.skip_until /\}/ i = i+1 drops[i] = drop end puts drops.inspect drops.each do |drop| #content[drop[:from], drop[:to]] = "...Partial content..." end content end The difference is, that I now have a hash called "drops" with properties for all my partials to render in there. For each partial I create a temporary hash called "drop" that I apply to "drops" in the end. Then I loop over each drop and replace the {some_partial foo:bar} stuff with a partial (like you wanted: after the StringScanner has finished). As you can see, I''m doing a drops.inspect, and it outputs this: {1=>{:to=>42, :partial=>"contact_form", :arguments=>{:hello=>"you", :bar=>"foos", :foo=>"bars"}, :from=>0}, 2=>{:to=>88, :partial=>"contact_form", :arguments=>{:hi=>"you", :its=>"a_good_day"}, :from=>43}} It looks right but when I uncomment one of the last lines (content[drop[:from], drop[:to]] = "...) I get this error: Symbol as array index But I''m not using an array!.. Am I missing something? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 9 Oct 2008, at 11:16, David Trasbo wrote:> > Frederick Cheung wrote: >> On 9 Oct 2008, at 10:15, David Trasbo wrote: >> >>> I don''t see other possibilities. >> accumulate the replacements you need and do them at the end (last one >> first) >>>> your locals are things like bar=foo (and i imagine the values are >>>> blank) >>> >>> Unfortunately that is not true. When I comment out the >>> "content[from, >>> to] = render..." line and put "puts debug arguments" on the line >>> before >>> so it looks like this: >>> >> given how :locals is handled it seems highly likely >>> foo: bars >>> bar: foos >>> >> It would be a lot simpler to just stick a breakpoint in there (or >> output arguments.inspect) > > I''m quite close to the solution now, my method now looks like this: > > def dropify(content) > s = StringScanner.new(content) > drops = {} > i = 0 > while s.scan_until /\{/ > drop = {} > drop[:from] = s.pointer - 1 > drop[:arguments] = {} > drop[:partial] = s.scan /\w+/ > s.skip /\s+/ > while argument = s.scan( /\w+:\w+/) > name, value = argument.split(/:/) > drop[:arguments][name.to_sym] = value > s.skip /\s+/ > end > drop[:to] = s.pointer+1 > s.skip_until /\}/ > i = i+1 > drops[i] = drop > end > puts drops.inspect > drops.each do |drop| > #content[drop[:from], drop[:to]] = "...Partial content..." > end > content > end > > The difference is, that I now have a hash called "drops" with > properties > for all my partials to render in there. For each partial I create a > temporary hash called "drop" that I apply to "drops" in the end. > > Then I loop over each drop and replace the {some_partial foo:bar} > stuff > with a partial (like you wanted: after the StringScanner has > finished). > > As you can see, I''m doing a drops.inspect, and it outputs this: > > {1=>{:to=>42, :partial=>"contact_form", :arguments=>{:hello=>"you", > :bar=>"foos", :foo=>"bars"}, :from=>0}, 2=>{:to=>88, > :partial > =>"contact_form", :arguments=>{:hi=>"you", :its=>"a_good_day"}, > :from=>43}} > > It looks right but when I uncomment one of the last lines > (content[drop[:from], drop[:to]] = "...) I get this error: > > Symbol as array index > > But I''m not using an array!.. Am I missing something?Yes :-) here drop is an array (the first element is the key, the second is the value) Typically one using each with a hash, one does some_hash.each do |key, value| ... end lastly, why is drops a hash at all and not an array ? Fred> > -- > Posted via http://www.ruby-forum.com/. > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:>> But I''m not using an array!.. Am I missing something? > > Yes :-) > here drop is an array (the first element is the key, the second is the > value) > Typically one using each with a hash, one does > some_hash.each do |key, value| > ... > endAll right. Fixed. :)> lastly, why is drops a hash at all and not an array ?I don''t know, that is changed now, too. Thanks. One last question: I''m currently replacing the {some_partial foo:bar} to the partial like this: content[drop[:from], drop[:to]] = render(:partial => "drops/#{drop[:partial]}", :locals => drop[:arguments]) But this is very buggy. The [fixnum, fixnum] method assumes that the new thing (in my case, a partial) is of the same length as the {some_partial foo:bar}. That means the partial is "swallowing" up the next partial if it''s too long. If my partial looks like this: This is a test drop. Please don''t edit or remove it. and I do {some_partial foo:bar} twice I get this output: This is a test drop. Please don’t edit or remove it. don’t edit or remove it. In this case the partial is longer than the {some_partial} and some of the second instance of the partial disappears. How can I force Ruby to replace the characters between to positions with a longer string? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 9 Oct 2008, at 15:14, David Trasbo wrote:> > > In this case the partial is longer than the {some_partial} and some of > the second instance of the partial disappears. How can I force Ruby to > replace the characters between to positions with a longer string?You could fiddle with insert or something like that. There is another way of doing it: Say you''ve determine the two sections to replace are between positions 20 and 40 and then between 100 and 120 you would do result = "" result << original_string[0, 20] result << render of first section result << original_string[40, 60] result << render of last section result << original_string[120, original_string.length - 120 Fred --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:>> In this case the partial is longer than the {some_partial} and some of >> the second instance of the partial disappears. How can I force Ruby to >> replace the characters between to positions with a longer string? > > You could fiddle with insert or something like that. There is another > way of doing it: > Say you''ve determine the two sections to replace are between positions > 20 and 40 and then between 100 and 120 > you would do > > result = "" > result << original_string[0, 20] > result << render of first section > result << original_string[40, 60] > result << render of last section > result << original_string[120, original_string.length - 120That''s seems a little complicated (and I don''t see the flexibility of it, either) but now I''m using the String#insert and at the end I do a String#gsub to remove the {some_partial foo:bar}''s. So my final method looks like this: =========def dropify(content) s = StringScanner.new(content) drops = Array.new while s.scan_until(/\{/) drop = {} drop[:from] = s.pointer - 1 drop[:arguments] = {} drop[:partial] = s.scan(/\w+/) s.skip /\s+/ while argument = s.scan(/\w+:\w+/) name, value = argument.split(/:/) drop[:arguments][name.to_sym] = value s.skip /\s+/ end s.skip_until /\}/ drops << drop end drops.reverse! drops.each do |drop| content.insert(drop[:from], render(:partial => "drops/#{drop[:partial]}", :locals => drop[:arguments])) end content.gsub!(/\{\w+.*\}/, "") content end ========= Thanks for your help! I hope some of you can use this method as well. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 9 Oct 2008, at 15:52, David Trasbo wrote:> > Frederick Cheung wrote: > >>> In this case the partial is longer than the {some_partial} and >>> some of >>> the second instance of the partial disappears. How can I force >>> Ruby to >>> replace the characters between to positions with a longer string? >> >> You could fiddle with insert or something like that. There is another >> way of doing it: >> Say you''ve determine the two sections to replace are between >> positions >> 20 and 40 and then between 100 and 120 >> you would do >> >> result = "" >> result << original_string[0, 20] >> result << render of first section >> result << original_string[40, 60] >> result << render of last section >> result << original_string[120, original_string.length - 120 > > That''s seems a little complicated (and I don''t see the flexibility of > it, either) but now I''m using the String#insert and at the end I do a > String#gsub to remove the {some_partial foo:bar}''s. >It avoids the need to maintain the drop array (and also means that you don''t need a gsub that as is i believe will remove the wrong content if there are more than one partial (because the * is greedy) you could have something like def dropify(content) s = StringScanner.new(content) output = "" previous_end = 0 while s.scan_until(/\{/) output << content[previous_end, s.pointer - previous_end] partial = s.scan(/\w+/) s.skip /\s+/ arguments = {} while argument = s.scan(/\w+:\w+/) name, value = argument.split(/:/) arguments[name.to_sym] = value s.skip /\s+/ end s.skip_until /\}/ previous_end = s.pointer end output << content[s.pointer, content.length - s.pointer] end which is marginally simpler (the above could contain off by 1 errors in the various offsets). Fred> So my final method looks like this: > > =========> def dropify(content) > s = StringScanner.new(content) > drops = Array.new > while s.scan_until(/\{/) > drop = {} > drop[:from] = s.pointer - 1 > drop[:arguments] = {} > drop[:partial] = s.scan(/\w+/) > s.skip /\s+/ > while argument = s.scan(/\w+:\w+/) > name, value = argument.split(/:/) > drop[:arguments][name.to_sym] = value > s.skip /\s+/ > end > s.skip_until /\}/ > drops << drop > end > drops.reverse! > drops.each do |drop| > content.insert(drop[:from], render(:partial => > "drops/#{drop[:partial]}", :locals => drop[:arguments])) > end > content.gsub!(/\{\w+.*\}/, "") > content > end > =========> > Thanks for your help! I hope some of you can use this method as well. > -- > Posted via http://www.ruby-forum.com/. > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:>> That''s seems a little complicated (and I don''t see the flexibility of >> it, either) but now I''m using the String#insert and at the end I do a >> String#gsub to remove the {some_partial foo:bar}''s. >> > > It avoids the need to maintain the drop array (and also means that you > don''t need a gsub that as is i believe will remove the wrong content > if there are more than one partial (because the * is greedy)I admit the gsub was an emergency solution, and yes, there are a risk that it will strip the wrong content.> you could have something like > > def dropify(content) > s = StringScanner.new(content) > output = "" > previous_end = 0 > while s.scan_until(/\{/) > output << content[previous_end, s.pointer - previous_end] > partial = s.scan(/\w+/) > s.skip /\s+/ > arguments = {} > while argument = s.scan(/\w+:\w+/) > name, value = argument.split(/:/) > arguments[name.to_sym] = value > s.skip /\s+/ > end > s.skip_until /\}/ > previous_end = s.pointer > end > output << content[s.pointer, content.length - s.pointer] > endI''ve been taking a look at your code and it looks interesting. But the only thing I can''t figure out is where (and how) you''ld render the partial in the code above. I''ve been testing your method and something is wrong. E.g. if you have this content: ---------- {test} Lorem ipsum dolor sit amet. {test} Lorem ipsum dolor sit amet. ---------- you''ll get absolutely nothing back. I tried changing the 6th line to this: output << content[previous_end, s.pointer] Still wrong: ---------- { Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. {test} Lorem ipsum dolor sit amet. ---------- Did your method work for you, or what?> which is marginally simpler (the above could contain off by 1 errors > in the various offsets).What is "off by 1 errors"? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Oct 15, 8:00 am, David Trasbo <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> Frederick Cheung wrote: > > Did your method work for you, or what?yeah i left out that bit by accident. you should do that (ie output << render(...)) after I set previous_end at the end of the loop> > which is marginally simpler (the above could contain off by 1 errors > > in the various offsets). > > What is "off by 1 errors"?some of the offsets might be off by 1 (eg someplaces where it says pointer it might need to be s.pointer-1 etc..). More generally I just bashed that out in Mail so I expect that there''s the odd mistake like that in there. Fred> -- > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:>> Did your method work for you, or what? > > yeah i left out that bit by accident. you should do that (ie output << > render(...)) after I set previous_end at the end of the loopOkay, thanks!>> What is "off by 1 errors"? > > some of the offsets might be off by 1 (eg someplaces where it says > pointer it might need to be s.pointer-1 etc..). More generally I just > bashed that out in Mail so I expect that there''s the odd mistake > like that in there.All right, with my new knowledge I''ve changed your method a little bit and it works perfectly well. So this is the new final version of the method: =========def dropify(content) s = StringScanner.new(content) output = "" previous_end = 0 while s.scan_until(/\{/) output << content[previous_end, s.pointer - previous_end - 1] partial = s.scan(/\w+/) s.skip /\s+/ arguments = {} while argument = s.scan(/\w+:\w+/) name, value = argument.split(/:/) arguments[name.to_sym] = value s.skip /\s+/ end s.skip_until /\}/ previous_end = s.pointer output << render(:partial => "drops/#{partial}", :locals => arguments) end output << content[s.pointer, content.length - s.pointer] end ========= Notice that in the 6th line i subtract s.pointer-previous_end by 1 and that''s what made it work. Thanks for your help, Fred! -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
David Trasbo wrote:> =========> def dropify(content) > s = StringScanner.new(content) > output = "" > previous_end = 0 > while s.scan_until(/\{/) > output << content[previous_end, s.pointer - previous_end - 1] > partial = s.scan(/\w+/) > s.skip /\s+/ > arguments = {} > while argument = s.scan(/\w+:\w+/) > name, value = argument.split(/:/) > arguments[name.to_sym] = value > s.skip /\s+/ > end > s.skip_until /\}/ > previous_end = s.pointer > output << render(:partial => "drops/#{partial}", :locals => > arguments) > end > output << content[s.pointer, content.length - s.pointer] > end > =========Okay, I actually have a concern about this method. Right now it only accepts this kind of syntax: {test foo:foo_bar} Since spaces are not covered by \w+ this is not accepted: {test foo:foo bar} So I tried changing \w+ to .+ but of course that is never going to work. E.g. if I try to pass multiple arguments to the partial like this: {test foo:foo bar bar:bar foo} then only one argument will only be passed (foo) and it will have this value: "foo bar bar" because the .+ includes that. But what about putting quotation marks around it? ".+" Still the same problem. Now foo will just have this value: "“foo bar” bar". So, here is my question: How can I make this method accept multiple arguments without being limited to that the values have to match "\w+"? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
how about doing something like this logic scan your content looking for "{" store everything until your next "}" into a string variable # now string = "test foo:foo bar bar:bar foo" split your string by spaces into an array # now array = ["test", "foo:foo", "bar", "bar:bar", "foo"] loop through your array new_array = [] index = 0 array.each do |a| if a does not contain ":" index = index + 1 partial = a args = {} new_array[index] = [partial, args] else args = new_array[index][2] # should be a hash name, value = a.split(/:/) args[name.to_sym] = value # add new args to hash new_array[index][2] = args # store hash back into the array end end # now new_array = [["foo", {foo => "foo"}], ["bar", {bar => "bar"}], ["foo", {}]] loop through this and render partials new_array.each do |a| partial = a[1] arguments = a[2] output << render(:partial => "drops/#{partial}", :locals => arguments) end i am sure there are errors and bugs but i think the basic logic should work. it will probably turn out to be fairly clean and readable if refactored into a few methods. On Oct 15, 6:01 am, David Trasbo <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> David Trasbo wrote: > > =========> > def dropify(content) > > s = StringScanner.new(content) > > output = "" > > previous_end = 0 > > while s.scan_until(/\{/) > > output << content[previous_end, s.pointer - previous_end - 1] > > partial = s.scan(/\w+/) > > s.skip /\s+/ > > arguments = {} > > while argument = s.scan(/\w+:\w+/) > > name, value = argument.split(/:/) > > arguments[name.to_sym] = value > > s.skip /\s+/ > > end > > s.skip_until /\}/ > > previous_end = s.pointer > > output << render(:partial => "drops/#{partial}", :locals => > > arguments) > > end > > output << content[s.pointer, content.length - s.pointer] > > end > > =========> > Okay, I actually have a concern about this method. Right now it only > accepts this kind of syntax: > > {test foo:foo_bar} > > Since spaces are not covered by \w+ this is not accepted: > > {test foo:foo bar} > > So I tried changing \w+ to .+ but of course that is never going to work. > E.g. if I try to pass multiple arguments to the partial like this: > > {test foo:foo bar bar:bar foo} > > then only one argument will only be passed (foo) and it will have this > value: "foo bar bar" because the .+ includes that. > > But what about putting quotation marks around it? > > ".+" > > Still the same problem. Now foo will just have this value: "“foo bar” > bar". So, here is my question: How can I make this method accept > multiple arguments without being limited to that the values have to > match "\w+"? > > -- > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Scott Nj wrote:> how about doing something like this logicIt''s good to hear your oppinion on it, but I actually like Fred''s approach on it a little better. It is clean and fairly readable.> i am sure there are errors and bugs but i think the basic logic should > work. it will probably turn out to be fairly clean and readable if > refactored into a few methods.The thing is that Fred helped me putting together a method and he''s spent a lot of time fixing all the bugs I found. Why would I completely remake the method just to find a bunch of new bugs? Okay, I think I should describe my tricky problem a little further. This is it: The method does a scan_until(/\{/) which means it stops when meeting a curly brace and starts looking for something matching \w+ immediately after the curly brace. That is the partial to render. The string looks like this: {test_partial foo:"bar foo" bar:"foo bar"} Fine. Then it starts looking for arguments immediately after the partial and a space. My problem is that the method only supports values that matches \w+. I would like values to be able to match .* or .+. Now, my problem is that when I change the method so that the value should match .+ it doesn''t only take the characters between the first and the second quotation sign (name: "foo", value: "bar foo"), it actually goes on at takes the next quotation sign too (name: "foo", value: "bar foo" bar:"). So that we actually get a value that contains the right value and then the name of the NEXT argument afterwards. How can I solve this? If you need further details, just ask. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung wrote:> On 16 Oct 2008, at 08:36, David Trasbo wrote: > >> partial >> and a space. My problem is that the method only supports values that >> matches \w+. I would like values to be able to match .* or .+. >> > Greedy things like .* are almost always dangerous as they make you > consume the entire string. typically you''d want to scan or scan_until > the first occurence of somethingYes.> the following modification to the previous solution does that: > > def dropify(content) > s = StringScanner.new(content) > output = "" > previous_end = 0 > while s.scan_until(/\{/) > output << content[previous_end, s.pointer - previous_end - 1] > partial = s.scan(/\w+/) > s.skip /\s+/ > arguments = {} > while label= s.scan(/(\w+):"/) > name=s[1] > value = s.scan /[^"]+/ > arguments[name.to_sym] = value > s.skip /"\s+/ > end > s.skip_until /\}/ > previous_end = s.pointer > puts arguments.inspect > end > endThis works perfectly. I modified it a little bit for my needs. This method supports multiple arguments with values containing any kind of characters: def dropify(content) s = StringScanner.new(content) output = "" previous_end = 0 while s.scan_until(/\{/) output << content[previous_end, s.pointer - previous_end - 1] partial = s.scan(/\w+/) s.skip /\s+/ arguments = {} while label= s.scan(/(\w+):"/) name = s[1] value = s.scan /[^"]+/ arguments[name.to_sym] = value s.skip /"\s+/ end s.skip_until /\}/ previous_end = s.pointer output << render(:partial => "drops/#{partial}", :locals => arguments) end output << content[s.pointer, content.length - s.pointer] end> Having scanned \w+:" (ie a label and the opening quote mark) we > consume all non " characters and says those are the arguments. then we > skip over the closing " and any whitespace > > dropify(''{test_partial foo:"bar foo" bar:"foo bar"}'') > > outputs > > {:foo=>"bar foo", :bar=>"foo bar"}Great! Thanks again for your help, Fred. David T. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---