Rack using String#each equals Ruby 1.9.1p2 fail

96 views
Skip to first unread message

Peter Cooper

unread,
Dec 9, 2008, 10:23:48 PM12/9/08
to Rack Development
I was just getting edge Rails (2.3.0) running on Ruby 1.9.1preview2
but ran into a problem with Rack.

In the webrick handler (lib/rack/handler/webrick.rb), Rack is using
a .each method when working with the headers (line 47). Unfortunately,
Ruby 1.9 does not implement String#each so requests are unsuccessful:

Simply changing:
vs.each { |v|
to
vs.split($/).each { |v|
.. should resolve the issue.

I note that this technique is used in other handlers, however, so
instead of submitting a patch when I am not particularly familiar with
the Rack code base, I'm just letting you know so it can be factored in
at some point - especially as it's a minor adjustment.

For the time being, I'm monkeypatching String#each support and might
continue to do so anyway because it seems a lot of people use it in
their 1.8 libraries.. :) Monkey patch is as simple as:

class String
def each
self.split($/).each { |e| yield e }
end
end

Alternatively, this may have already been solved and I'm unable to
find the latest version of the code, but the version on Github appears
to have this issue too and that appears to be updated regularly.

Cheers,
Peter Cooper
http://www.petercooper.co.uk/

James Tucker

unread,
Dec 10, 2008, 7:50:01 AM12/10/08
to rack-...@googlegroups.com

On 10 Dec 2008, at 03:23, Peter Cooper wrote:

> I was just getting edge Rails (2.3.0) running on Ruby 1.9.1preview2
> but ran into a problem with Rack.

s/with Rack//

> In the webrick handler (lib/rack/handler/webrick.rb), Rack is using
> a .each method when working with the headers (line 47). Unfortunately,
> Ruby 1.9 does not implement String#each so requests are unsuccessful

String bodies are evil, and should be punished. (Rails is wrong).

> I note that this technique is used in other handlers, however, so
> instead of submitting a patch when I am not particularly familiar with
> the Rack code base, I'm just letting you know so it can be factored in
> at some point - especially as it's a minor adjustment.

Specifically, the rack spec says:

=== The Body
The Body must respond to #each
and must only yield String values.
If the Body responds to #close, it will be called after iteration.
The Body commonly is an Array of Strings, the application
instance itself, or a File-like object.

Christian Neukirchen

unread,
Dec 10, 2008, 8:04:33 AM12/10/08
to rack-...@googlegroups.com

Do not use String bodies in 1.9.
(The .each fix is useful for multiple header values. Future revisions of
Rack probably will use an explicit .split for these. This is yet to
be decided.)

--
Christian Neukirchen <chneuk...@gmail.com> http://chneukirchen.org

Jeremy Kemper

unread,
Dec 10, 2008, 12:28:29 PM12/10/08
to rack-...@googlegroups.com
On Wed, Dec 10, 2008 at 4:50 AM, James Tucker <jftu...@gmail.com> wrote:
> On 10 Dec 2008, at 03:23, Peter Cooper wrote:
>
>> I was just getting edge Rails (2.3.0) running on Ruby 1.9.1preview2
>> but ran into a problem with Rack.
>
> s/with Rack//

Rack used to expect and encourage String bodies because #each behaved
as expected.


>> In the webrick handler (lib/rack/handler/webrick.rb), Rack is using
>> a .each method when working with the headers (line 47). Unfortunately,
>> Ruby 1.9 does not implement String#each so requests are unsuccessful
>
> String bodies are evil, and should be punished. (Rails is wrong).

"Strings are no longer Enumerable, so we've deprecated their use as
response bodies. (Rails needs to be updated)."


>> I note that this technique is used in other handlers, however, so
>> instead of submitting a patch when I am not particularly familiar with
>> the Rack code base, I'm just letting you know so it can be factored in
>> at some point - especially as it's a minor adjustment.
>
> Specifically, the rack spec says:
>
> === The Body
> The Body must respond to #each
> and must only yield String values.
> If the Body responds to #close, it will be called after iteration.
> The Body commonly is an Array of Strings, the application
> instance itself, or a File-like object.

Which behaved as expected with older Rubies.

Many Rack apps use String bodies. Rack::Lint does not raise on String
bodies. Rack's own specs use String bodies.

Perhaps Rack should simply accept String bodies in 1.9 too?

jeremy

Ezra Zygmuntowicz

unread,
Dec 10, 2008, 12:31:13 PM12/10/08
to rack-...@googlegroups.com
>
> Which behaved as expected with older Rubies.
>
> Many Rack apps use String bodies. Rack::Lint does not raise on String
> bodies. Rack's own specs use String bodies.
>
> Perhaps Rack should simply accept String bodies in 1.9 too?

I think this is the right way to go. Even if you just alias each to
each_line in String on 1.9 it will work just fine.

Ezra


Ezra Zygmuntowicz

unread,
Dec 10, 2008, 12:33:47 PM12/10/08
to rack-...@googlegroups.com
>>
>
> Which behaved as expected with older Rubies.
>
> Many Rack apps use String bodies. Rack::Lint does not raise on String
> bodies. Rack's own specs use String bodies.
>
> Perhaps Rack should simply accept String bodies in 1.9 too?


Right now in merb we use a StreamWrapper to wrap the response body
which in merb can be a string or a Proc or a file handle. If its a
proc we do the streaming dance and if it is a string we just call
string.each_line when each gets called by the rack handlers. This
allows for streaming and for steing bodies to work on 1.9

http://github.com/wycats/merb/tree/master/merb-core/lib/merb-core/rack/stream_wrapper.rb

Cheers-

Ezra Zygmuntowicz
e...@engineyard.com

Jeremy Kemper

unread,
Dec 10, 2008, 12:44:08 PM12/10/08
to rack-...@googlegroups.com

Rails does the same. I'd love to see Rack take a more pragmatic stance
here, though!

http://github.com/rails/rails/tree/master/actionpack/lib/action_controller/rack_process.rb#L176

jeremy

Ezra Zygmuntowicz

unread,
Dec 10, 2008, 12:52:19 PM12/10/08
to rack-...@googlegroups.com

Me too. So what is the best way for rack to behave here then? I guess
the smallest change for 1.9 compat is to have rack call each_line if
the body is_a? String. But I'd like to see a more comprehensive
approach that maybe moves what both rails and merb seem to be doing
down into the handlers?

-Ezra

Joshua Peek

unread,
Dec 10, 2008, 12:56:53 PM12/10/08
to rack-...@googlegroups.com
What happened to body.respond_to?(:to_str) Rack::Response still checks for this.

if body.respond_to? :to_str
write body.to_str
elsif body.respond_to?(:each)
body.each { |part|
write part.to_s
}
else
raise TypeError, "stringable or iterable required"
end

Christian Neukirchen

unread,
Dec 11, 2008, 7:23:18 AM12/11/08
to rack-...@googlegroups.com
On Wed, Dec 10, 2008 at 6:28 PM, Jeremy Kemper <jer...@bitsweat.net> wrote:
> Many Rack apps use String bodies. Rack::Lint does not raise on String
> bodies. Rack's own specs use String bodies.

Rack::Lint will raise on String bodies, if you use 1.9, no?

String bodies are a bad idea---they cause overhead for every line.
If you already have the whole string, just put it into an Array.

James Tucker

unread,
Dec 11, 2008, 11:40:32 AM12/11/08
to rack-...@googlegroups.com

On 11 Dec 2008, at 12:23, Christian Neukirchen wrote:

>
> On Wed, Dec 10, 2008 at 6:28 PM, Jeremy Kemper <jer...@bitsweat.net>
> wrote:
>> Many Rack apps use String bodies. Rack::Lint does not raise on String
>> bodies. Rack's own specs use String bodies.
>
> Rack::Lint will raise on String bodies, if you use 1.9, no?
>
> String bodies are a bad idea---they cause overhead for every line.
> If you already have the whole string, just put it into an Array.

Well plus it does an implicit split on the string. Also it's adversely
affected by ruby's magic globals.

Reply all
Reply to author
Forward
0 new messages