In Ruby.tmbundle/Support/RubyMate, when I run the file "test.rb" using the command-R key combination in TextMate, the HTML window produces:
Library/Application Support/TextMate/Bundles/Ruby.tmbundle/Support/RubyMate/run_script.rb:65:in `block in ': undefined method `map' for "that\xE2\x80\x99s nice\n":String (NoMethodError) from /Library/Application
...plus the call chain.
When I rename the file to "bigfoo.rb", command-R functions correctly, although I get some method errors as part of the HTML display; a different issue.
Line 65 of run_script.rb, and also line 92 ("out.join"), seem to be expecting an Array, but my printing out the class of the argument "str" indicates it's a string.
As I said, I'm a newbie to Ruby, so I'm not really confident of my analysis here. One could change "str.map" to "str.each_line", but then I'm not sure what to do with "out.join", unless it's simply to return "out" at that point.
Or maybe I'm completely off-base.
Best, Charles
On Aug 24, 2008, at 7:16 PM, Charles Turner wrote:
In Ruby.tmbundle/Support/RubyMate, when I run the file "test.rb" using the command-R key combination in TextMate, the HTML window produces:
Library/Application Support/TextMate/Bundles/Ruby.tmbundle/Support/RubyMate/ run_script.rb:65:in `block in ': undefined method `map' for "that\xE2\x80\x99s nice\n":String (NoMethodError) from /Library/Application
...plus the call chain.
In Ruby 1.8, you can map() over the lines in a String. Ruby 1.9 no longer allows this. Thus, we need a new strategy.
We need something that works in both places, so we need to check for the new 1.9 method lines and map() over it instead, if present. The code would be something like:
str.send(str.respond_to?(:lines) ? :lines, :to_s).map { … }
Hope that helps.
James Edward Gray II
On Sun, 24 Aug 2008 20:08:48 -0500, James Gray wrote:
We need something that works in both places, so we need to check for the new 1.9 method lines and map() over it instead, if present. The code would be something like:
str.send(str.respond_to?(:lines) ? :lines, :to_s).map { … }
Hope that helps.
Hi James-
Thanks for your suggestion. The solution is a bit tricky, though. I think I have to test for String's support of :map in 1.8, because :each_line is supported in both 1.8 and 1.9.
In 1.8, you can do: a.map but in 1.9, I think you have to do: a.each_line.to_a.map
The next trick is sending a symbol. It looks like in 1.8 you can say "a.send(:map)", but the equivalent "a.send(:each_line.to_a.map)" isn't a valid symbol reference in Ruby.
I rewrote your suggestion as:
a.respond_to?(:map) ? a.map : a.each_line.to_a.map do |line| print line end
which works for 1.9, but doesn't in 1.8, I think because of the conditional's relation the "do" block.
Anyway, I'll keep working at it, and thanks again for the knowledge!
Best, Charles
On Aug 25, 2008, at 5:12 AM, Charles Turner wrote:
On Sun, 24 Aug 2008 20:08:48 -0500, James Gray wrote:
We need something that works in both places, so we need to check for the new 1.9 method lines and map() over it instead, if present. The code would be something like:
str.send(str.respond_to?(:lines) ? :lines, :to_s).map { … }
Thanks for your suggestion. The solution is a bit tricky, though. I think I have to test for String's support of :map in 1.8, because :each_line is supported in both 1.8 and 1.9.
In 1.8, you can do: a.map but in 1.9, I think you have to do: a.each_line.to_a.map
The next trick is sending a symbol. It looks like in 1.8 you can say "a.send(:map)", but the equivalent "a.send(:each_line.to_a.map)" isn't a valid symbol reference in Ruby.
I rewrote your suggestion as:
a.respond_to?(:map) ? a.map : a.each_line.to_a.map do |line| print line end
which works for 1.9, but doesn't in 1.8, I think because of the conditional's relation the "do" block.
Anyway, I'll keep working at it, and thanks again for the knowledge!
I have some changes pending that I think will fix this. Mind holding off for a bit?
―Alex
On Mon, 25 Aug 2008 08:51:44 +0200, Alex Ross wrote:
I have some changes pending that I think will fix this. Mind holding off for a bit?
Oh, sure, Alex. It's something I ran across while reading the Ruby bundle code, not in my day-to-day programming. Lack of a soluion is hardly holding me back.
Best, Charles
On Aug 24, 2008, at 10:12 PM, Charles Turner wrote:
On Sun, 24 Aug 2008 20:08:48 -0500, James Gray wrote:
We need something that works in both places, so we need to check for the new 1.9 method lines and map() over it instead, if present. The code would be something like:
str.send(str.respond_to?(:lines) ? :lines, :to_s).map { … }
Hope that helps.
Hi James-
Thanks for your suggestion. The solution is a bit tricky, though. I think I have to test for String's support of :map in 1.8, because :each_line is supported in both 1.8 and 1.9.
In 1.8, you can do: a.map but in 1.9, I think you have to do: a.each_line.to_a.map
You didn't read my code very well. Please scroll up and have another look. :)
I didn't use each_line() because it is available in both versions. I used the new lines() method, added in 1.9:
$ ruby_dev -ve 'puts "one\ntwo".lines.map { |l| l.capitalize }' ruby 1.9.0 (2008-03-01 revision 15664) [i686-darwin9.2.0] One Two
The next trick is sending a symbol. It looks like in 1.8 you can say "a.send(:map)", but the equivalent "a.send(:each_line.to_a.map)" isn't a valid symbol reference in Ruby.
Those two pieces of code are not equivalent. In the first, you send() a Symbol message to the object. In the second, you are calling to_a() on a Symbol.
I promise that send() still works in Ruby 1.9:
$ ruby_dev -ve 'p "one".send(:capitalize)' ruby 1.9.0 (2008-03-01 revision 15664) [i686-darwin9.2.0] "One"
I rewrote your suggestion as:
a.respond_to?(:map) ? a.map : a.each_line.to_a.map do |line| print line end
which works for 1.9, but doesn't in 1.8, I think because of the conditional's relation the "do" block.
The reason it works in 1.9 is that the standard enumerator library was moved into the core. With this move came the enhancement that most iterators now return an Enumerable::Enumerator when called without a block. Thus, in 1.9, it is legal to call map() without a block as you do above. The same is not legal in 1.8.
Hope that answers some of your questions.
James Edward Gray II
On Mon, 25 Aug 2008 07:39:26 -0500, James Gray wrote:
str.send(str.respond_to?(:lines) ? :lines, :to_s).map { … }
You didn't read my code very well. Please scroll up and have another look. :)
Please forgive my ignorance of Ruby. I was confused by the comma after :lines, which my Rubies complain about. I substituted a colon, but maybe (again) that's not what you're trying to say?
I read your above as: "if the receiver responds to :lines, send :lines, else send :to_s", which in 1.8's case is effectively a NoOp: a conversion of a string to a string?
I do see now that :lines is a 1.9-only method, and so your test is a smart one.
The next trick is sending a symbol. It looks like in 1.8 you can say "a.send(:map)", but the equivalent "a.send(:each_line.to_a.map)" isn't a valid symbol reference in Ruby.
Those two pieces of code are not equivalent. In the first, you send() a Symbol message to the object. In the second, you are calling to_a() on a Symbol.
Thanks for the clarification/analysis of my (incorrect) code!
a.respond_to?(:map) ? a.map : a.each_line.to_a.map do |line| print line end
which works for 1.9, but doesn't in 1.8
Thus, in 1.9, it is legal to call map() without a block as you do above. The same is not legal in 1.8.
Hope that answers some of your questions.
Again, thanks for the clarification/education.
Best, Charles
On Aug 25, 2008, at 8:07 AM, Charles Turner wrote:
On Mon, 25 Aug 2008 07:39:26 -0500, James Gray wrote:
str.send(str.respond_to?(:lines) ? :lines, :to_s).map { … }
You didn't read my code very well. Please scroll up and have another look. :)
Please forgive my ignorance of Ruby. I was confused by the comma after :lines, which my Rubies complain about. I substituted a colon, but maybe (again) that's not what you're trying to say?
Oops, yeah, that was a typo. Sorry about that.
You fixed it correctly. Here's what it should have been:
str.send(str.respond_to?(:lines) ? :lines : :to_s).map { … }
I read your above as: "if the receiver responds to :lines, send :lines, else send :to_s", which in 1.8's case is effectively a NoOp: a conversion of a string to a string?
Right.
James Edward Gray II