Feature/SPEC Freeze

8 views
Skip to first unread message

Christian Neukirchen

unread,
Apr 23, 2009, 3:48:11 PM4/23/09
to Rack Development

I'm releasing 1.0 on Saturday.

Please post all SPEC changes that are not in rack/master now and that
go into 1.0, AGAIN to this thread.

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

Joshua Peek

unread,
Apr 23, 2009, 4:47:38 PM4/23/09
to rack-...@googlegroups.com
On Thu, Apr 23, 2009 at 2:48 PM, Christian Neukirchen
<chneuk...@gmail.com> wrote:
>
>
> I'm releasing 1.0 on Saturday.
>
> Please post all SPEC changes that are not in rack/master now and that
> go into 1.0, AGAIN to this thread.

Can you please reconsider Jeremy Kemper's amendment to change
"body.each should yield String" to "body.each should yield values
which respond to to_s".


--
Joshua Peek

Yehuda Katz

unread,
Apr 23, 2009, 4:51:25 PM4/23/09
to rack-...@googlegroups.com
+1

-- Yehuda
--
Yehuda Katz
Developer | Engine Yard
(ph) 718.877.1325

Christian Neukirchen

unread,
Apr 23, 2009, 5:10:49 PM4/23/09
to rack-...@googlegroups.com
Joshua Peek <jo...@joshpeek.com> writes:

> Can you please reconsider Jeremy Kemper's amendment to change
> "body.each should yield String" to "body.each should yield values
> which respond to to_s".

Not worth the hassle IMO.

Jeremy Kemper

unread,
Apr 23, 2009, 8:48:39 PM4/23/09
to rack-...@googlegroups.com
On Thu, Apr 23, 2009 at 2:10 PM, Christian Neukirchen
<chneuk...@gmail.com> wrote:
>
> Joshua Peek <jo...@joshpeek.com> writes:
>
>> Can you please reconsider Jeremy Kemper's amendment to change
>> "body.each should yield String" to "body.each should yield values
>> which respond to to_s".
>
> Not worth the hassle IMO.

The hassle level is pretty low. Few middlewares (3 of 25 in
rack-contrib) mutate the response body; all others are unaffected.

On the win side, we:
- sharpen the spec by requiring only what's needed
- trade a prickly instance_of? requirement for a light duck type
- gain conceptual purity: we don't actually *need* a String, just a
way of getting a string representation
- encourage middleware discipline, giving a clear, definitive way to
interact with the body
- increase the flexibility of rack applications, giving them all the
freedom that duck-typing affords

IO.write calls to_s on its argument so most handlers are naturally compatible.

Patch at http://github.com/jeremy/rack/commit/629d64b9bc3f3917b2665ee5f73eef702f4c9c62
For rack-contrib:
http://github.com/jeremy/rack-contrib/commit/dddcec843f247af2d40e2402e365ff8ad68e253b

Best,
jeremy

Christian Neukirchen

unread,
Apr 24, 2009, 11:03:48 AM4/24/09
to rack-...@googlegroups.com
Jeremy Kemper <jer...@bitsweat.net> writes:

> Patch at http://github.com/jeremy/rack/commit/629d64b9bc3f3917b2665ee5f73eef702f4c9c62

Sensible enough... hrm. Who has arguments *against* it?

Sam Roberts

unread,
Apr 24, 2009, 4:32:42 PM4/24/09
to rack-...@googlegroups.com
On Fri, Apr 24, 2009 at 8:03 AM, Christian Neukirchen
<chneuk...@gmail.com> wrote:
> Jeremy Kemper <jer...@bitsweat.net> writes:
>
>> Patch at http://github.com/jeremy/rack/commit/629d64b9bc3f3917b2665ee5f73eef702f4c9c62
>
> Sensible enough... hrm. Who has arguments *against* it?

#to_str is the correct method to use when duck-typing to strings.

Using #to_s is the equivalent of saying "must be derived from Object",
since Object implements #to_s:

Object.new.to_s
=> "#<Object:0x2ac82acc2ed8>"
{"a" => 4}.to_s
=> "a4"
IO.method(:open).to_s
=> "#<Method: IO.open>"

So every object in ruby can show up as the output, lint, and almost
certainly not do something useful. Buggy rack applications will lint
correctly, and cause random garbage such as the above to appear in the
output instead of throwing an exception.

Have fun debugging, and hope that the object doesn't have to_s aliased
to inspect, and that it doesn't dump your internal variables, like
passwds, to the http client.

If you believe a class to be a representation of a string, state your
belief by implementing to_str on it (or just convert instances to a
string before using them as rack output).

Cheers,
Sam

Jeremy Kemper

unread,
Apr 24, 2009, 6:40:18 PM4/24/09
to rack-...@googlegroups.com
On Fri, Apr 24, 2009 at 1:32 PM, Sam Roberts <vieu...@gmail.com> wrote:
>
> On Fri, Apr 24, 2009 at 8:03 AM, Christian Neukirchen
> <chneuk...@gmail.com> wrote:
>> Jeremy Kemper <jer...@bitsweat.net> writes:
>>
>>> Patch at http://github.com/jeremy/rack/commit/629d64b9bc3f3917b2665ee5f73eef702f4c9c62
>>
>> Sensible enough... hrm.  Who has arguments *against* it?
>
> #to_str is the correct method to use when duck-typing to strings.

The proposed duck type says "I can provide you with a string
representation" not "I am a string."


> Using #to_s is the equivalent of saying "must be derived from Object",
> since Object implements #to_s:
>
> Object.new.to_s
> => "#<Object:0x2ac82acc2ed8>"
> {"a" => 4}.to_s
> => "a4"
> IO.method(:open).to_s
> => "#<Method: IO.open>"
>
> So every object in ruby can show up as the output, lint, and almost
> certainly not do something useful. Buggy rack applications will lint
> correctly, and cause random garbage such as the above to appear in the
> output instead of throwing an exception.
>
> Have fun debugging, and hope that the object doesn't have to_s aliased
> to inspect, and that it doesn't dump your internal variables, like
> passwds, to the http client.

Ruby disagrees. IO#write requests string representations and the sky
has not fallen (mercifully).

> If you believe a class to be a representation of a string, state your
> belief by implementing to_str on it (or just convert instances to a
> string before using them as rack output).

Again, "provides a string" not "is a string" :)

Best,
jeremy

Sam Roberts

unread,
Apr 24, 2009, 7:49:40 PM4/24/09
to rack-...@googlegroups.com
On Fri, Apr 24, 2009 at 3:40 PM, Jeremy Kemper <jer...@bitsweat.net> wrote:
>
> On Fri, Apr 24, 2009 at 1:32 PM, Sam Roberts <vieu...@gmail.com> wrote:
>>
>> On Fri, Apr 24, 2009 at 8:03 AM, Christian Neukirchen
>> <chneuk...@gmail.com> wrote:
>>> Jeremy Kemper <jer...@bitsweat.net> writes:
>>>
>>>> Patch at http://github.com/jeremy/rack/commit/629d64b9bc3f3917b2665ee5f73eef702f4c9c62
>>>
>>> Sensible enough... hrm. Who has arguments *against* it?
>>
>> #to_str is the correct method to use when duck-typing to strings.
>
> The proposed duck type says "I can provide you with a string
> representation" not "I am a string."

Yes, but not correctly, that is the intended use of to_str.

See ruby's string.c:

VALUE
rb_string_value(ptr)
volatile VALUE *ptr;
{
VALUE s = *ptr;
if (TYPE(s) != T_STRING) { // caller wants a string, but object
is not a String object, so...
s = rb_str_to_str(s);
*ptr = s;
}
if (!RSTRING(s)->ptr) {
make_null_str(s);
}
return s;
}

VALUE
rb_str_to_str(str)
VALUE str;
{
return rb_convert_type(str, T_STRING, "String", "to_str"); //
ruby calls to_str to convert it
}

Seen in action:

irb(main):001:0> class TheFile; def to_str; "file.txt"; end; end
=> nil
irb(main):002:0> open(TheFile.new, "w")
=> #<File:file.txt>

This is not specific to open(), all ruby core methods that expects to
receive a "string" as an argument really expect to receive "an
instance of String, or an object that responds to to_str".

Its should already work for all rack adapters implemented in C,
whether intended or not.

The to_s is a useful facility pulled in from java, its nice to have
quick-and-dirty conversion to strings when doing console output.

Calling it willy-nilly anytime you'd like a string is "duck typing"
only if you believe everything is a duck.

>> If you believe a class to be a representation of a string, state your
>> belief by implementing to_str on it (or just convert instances to a
>> string before using them as rack output).
>
> Again, "provides a string" not "is a string" :)

This comment applies equally to #to_s and #to_str.

Sam

Jeremy Kemper

unread,
Apr 25, 2009, 12:50:13 AM4/25/09
to rack-...@googlegroups.com
On Fri, Apr 24, 2009 at 4:49 PM, Sam Roberts <vieu...@gmail.com> wrote:
>
> On Fri, Apr 24, 2009 at 3:40 PM, Jeremy Kemper <jer...@bitsweat.net> wrote:
>>
>> On Fri, Apr 24, 2009 at 1:32 PM, Sam Roberts <vieu...@gmail.com> wrote:
>>>
>>> On Fri, Apr 24, 2009 at 8:03 AM, Christian Neukirchen
>>> <chneuk...@gmail.com> wrote:
>>>> Jeremy Kemper <jer...@bitsweat.net> writes:
>>>>
>>>>> Patch at http://github.com/jeremy/rack/commit/629d64b9bc3f3917b2665ee5f73eef702f4c9c62
>>>>
>>>> Sensible enough... hrm.  Who has arguments *against* it?
>>>
>>> #to_str is the correct method to use when duck-typing to strings.
>>
>> The proposed duck type says "I can provide you with a string
>> representation" not "I am a string."
>
> Yes, but not correctly, that is the intended use of to_str.

I do not mean duck-types to string -- there lies the path to hell. I
mean duck-types to an object that has a string representation.

to_str says "You can use me anywhere you can use a String; I am a string."

to_s says "Give me a string representation."

There's a wealth of discussion on this confusing topic in old
ruby-talk threads. A notable example:
http://groups.google.com/group/ruby-talk-google/browse_thread/thread/360cd68a6120a826

Another: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/207123

>
> See ruby's string.c:
>
> VALUE
> rb_string_value(ptr)
>    volatile VALUE *ptr;
> {
>    VALUE s = *ptr;
>    if (TYPE(s) != T_STRING) {  // caller wants a string, but object
> is not a String object, so...
>        s = rb_str_to_str(s);
>        *ptr = s;
>    }
>    if (!RSTRING(s)->ptr) {
>        make_null_str(s);
>    }
>    return s;
> }

aka StringValue, used throughout Ruby C code to implicitly cast to the
internal string type so the object may be operated on using the C
string functions.

>
> VALUE
> rb_str_to_str(str)
>    VALUE str;
> {
>    return rb_convert_type(str, T_STRING, "String", "to_str");  //
> ruby calls to_str to convert it
> }
>
> Seen in action:
>
> irb(main):001:0> class TheFile; def to_str; "file.txt"; end; end
> => nil
> irb(main):002:0> open(TheFile.new, "w")
> => #<File:file.txt>
>
> This is not specific to open(), all ruby core methods that expects to
> receive a "string" as an argument really expect to receive "an
> instance of String, or an object that responds to to_str".

This is a great example of to_str abuse :)

TheFile behaves nothing like String; you're using to_str to explicitly
coerce it into one. That's what to_s is for!

>> "file.txt" == TheFile.new
=> false

Because String#== checks for to_str, but doesn't actually call it.

Tangentially, in Ruby 1.9 open calls to_path on its argument.

> Its should already work for all rack adapters implemented in C,
> whether intended or not.
>
> The to_s is a useful facility pulled in from java, its nice to have
> quick-and-dirty conversion to strings when doing console output.

Actually, to_s has been around from the beginning. to_str was added in
1.8 to help resolve this confusion between "duck types to string" and
"has a string representation."

> Calling it willy-nilly anytime you'd like a string is "duck typing"
> only if you believe everything is a duck.

In this case, everything *is* a duck. We're simply saying how to make
it quack. That's the essence of the spec: call to_s on a body part for
its string representation.

>
>>> If you believe a class to be a representation of a string, state your
>>> belief by implementing to_str on it (or just convert instances to a
>>> string before using them as rack output).
>>
>> Again, "provides a string" not "is a string" :)
>
> This comment applies equally to #to_s and #to_str.

It does not; it's the semantic difference between the two methods. The
distinction is thoroughly covered in the ruby-talk threads linked
above.

Best,
jeremy

Joshua Peek

unread,
Apr 25, 2009, 1:39:05 AM4/25/09
to rack-...@googlegroups.com
Its now Saturday, is there any chance we can still get this in Chris? :)

--
Joshua Peek

Ryan Tomayko

unread,
Apr 25, 2009, 4:12:17 AM4/25/09
to rack-...@googlegroups.com
On Thu, Apr 23, 2009 at 1:47 PM, Joshua Peek <jo...@joshpeek.com> wrote:
>

I thought we decided on a body wrapper class to go under Rack::Utils
for this? This just doesn't seem like it should require a spec change
to me. The producer of such a body can always ensure the desired
behavior.

Thanks,
Ryan

Christian Neukirchen

unread,
Apr 25, 2009, 6:03:28 AM4/25/09
to rack-...@googlegroups.com
Ryan Tomayko <r...@tomayko.com> writes:

> This just doesn't seem like it should require a spec change
> to me. The producer of such a body can always ensure the desired
> behavior.

Given the recent to_str/to_s discussion, I think that is a better
solution. Luckily, allowing to_str/to_s is backward-compatible to
Rack 0.9/1.0, so we can implement it without a major release.

Hongli Lai

unread,
Apr 25, 2009, 7:03:40 AM4/25/09
to Rack Development
On Apr 23, 9:48 pm, Christian Neukirchen <chneukirc...@gmail.com>
wrote:
> I'm releasing 1.0 on Saturday.
>
> Please post all SPEC changes that are not in rack/master now and that
> go into 1.0, AGAIN to this thread.

I'd like to propose the inclusion of the following spec changes:
http://github.com/FooBarWidget/rack/commits/master
(see 5611218134a and beyond)

Christian Neukirchen

unread,
Apr 25, 2009, 8:43:38 AM4/25/09
to rack-...@googlegroups.com
Hongli Lai <hon...@phusion.nl> writes:

> I'd like to propose the inclusion of the following spec changes:
> http://github.com/FooBarWidget/rack/commits/master
> (see 5611218134a and beyond)

Applied.

Your buffer patch needed this, by the way:

http://github.com/rack/rack/commit/1d85138ecad0d36c83b60630e22581ae6adf5f9e

Jeremy Kemper

unread,
Apr 25, 2009, 4:45:03 PM4/25/09
to rack-...@googlegroups.com
> Ryan Tomayko <r...@tomayko.com> writes:
>> This just doesn't seem like it should require a spec change
>> to me. The producer of such a body can always ensure the desired
>> behavior.

Having a Rack application provide a body wrapper that "fakes" this
spec does partially satisfy the final point here:

> On the win side, we:
> - sharpen the spec by requiring only what's needed
> - trade a prickly instance_of? requirement for a light duck type
> - gain conceptual purity: we don't actually *need* a String, just a way of getting a string representation
> - encourage middleware discipline, giving a clear, definitive way to interact with the body
> - increase the flexibility of rack applications, giving them all the freedom that duck-typing affords

In that the application may provide non-String objects *internally*.
The full benefits do not flow through Rack's veins; they're
constrained to a single application's frankenstein body. The proposal
aims to bring these win propositions to Rack, not to emulate them in a
particular app.

Instead, our imagination goes, we could inject a middleware that wraps
the body for all downstream middlewares and apps. This sounds kinda
plausible, but it unwittingly fractures Rack: everything downstream is
no longer Rack compliant.

My original proposal lingered on the last point -- the world of
flexibility this opens -- because it gets me all starry-eyed about
lazy Rack constellations, but that's a benefit of the SPEC change, not
the reason for it :)

On Sat, Apr 25, 2009 at 3:03 AM, Christian Neukirchen
<chneuk...@gmail.com> wrote:
>
> Given the recent to_str/to_s discussion, I think that is a better
> solution.  Luckily, allowing to_str/to_s is backward-compatible to
> Rack 0.9/1.0, so we can implement it without a major release.

I think the to_str/to_s question is resolved.

If we make this change in a later release, Rack 0.9/1.0 middlewares
that twiddle the body (such as ContentLength) may break.

Best,
jeremy

Jeremy Kemper

unread,
Apr 25, 2009, 5:18:26 PM4/25/09
to rack-...@googlegroups.com

Darn. I didn't see that 1.0 had already been released earlier today :(

jeremy

Reply all
Reply to author
Forward
0 new messages