Computer Science Canada

Ruby TYS

Author:  wtd [ Thu Sep 29, 2005 6:51 pm ]
Post subject:  Ruby TYS

Let's kick it off with a challenge.

Given a file containing dates in the format:

code:
092203
072105
061704


That is read into an array called 'dates'.

code:
["092203", "072105", "061704"]


Create a new array called 'new_dates' with each date in the format: mm/dd/yy, rather than mmddyy.

Don't use regular expressions or slices. Smile

Author:  Cervantes [ Fri Sep 30, 2005 9:17 pm ]
Post subject: 

Ruby:

new_dates = File::open("dates.txt").readlines.collect { |d| d[0..1] + "/" +d[2..3] + "/" + d[4..5] }
p new_dates

Rather messy block I've got there. Sad

Author:  wtd [ Sat Oct 01, 2005 1:58 pm ]
Post subject: 

Cervantes wrote:
Ruby:

new_dates = File::open("dates.txt").readlines.collect { |d| d[0..1] + "/" +d[2..3] + "/" + d[4..5] }
p new_dates

Rather messy block I've got there. Sad


code:
d[0..1]


Is a slice. Smile

Author:  wtd [ Fri Oct 28, 2005 5:46 pm ]
Post subject: 

Write an HTTP server in at most 4 lines of code (no semi-colons) that sits on port 2000 and simply sends "Hello world!" to any clients that connect.

Author:  rdrake [ Fri Nov 18, 2005 9:33 pm ]
Post subject: 

wtd wrote:
Write an HTTP server in at most 4 lines of code (no semi-colons) that sits on port 2000 and simply sends "Hello world!" to any clients that connect.
Could only get it down to 5.
code:
require 'socket'

socket = TCPServer.new('127.0.0.1', 2000)
newSock = socket.accept
request = newSock.gets
newSock.print "HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\nHello World!\r\n"
Any way I can make it shorter?

Author:  wtd [ Fri Nov 18, 2005 10:30 pm ]
Post subject: 

Well, that kinda works. It only connects to one client, though. Smile

On removing extraneous code... this line doesn't serve any purpose.

code:
request = newSock.gets

Author:  rdrake [ Sat Nov 19, 2005 11:11 am ]
Post subject: 

wtd wrote:
Well, that kinda works. It only connects to one client, though. Smile
The following will connect with an unlimited number of clients, but it's over the limit.
code:
require 'socket'
socket = TCPServer.new('127.0.0.1', 2000)
while newSock = socket.accept
    puts newSock.gets
    newSock.print "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n<html><head><title>Hello World!</title></head><body><p>Hello world!</p></body></html>\r\n"
    newSock.close
end


wtd wrote:
On removing extraneous code... this line doesn't serve any purpose.

code:
request = newSock.gets
That line was there so browsers could connect to it too. After playing around with different telnet clients, I've managed to get the code down to this.
code:
require 'socket'
socket = TCPServer.new('127.0.0.1', 2000)
socket.accept
newSock.print "Hello world!"
newSock.close
Any ideas how I could get this down smaller?

Author:  wtd [ Sat Nov 19, 2005 1:38 pm ]
Post subject: 

Untested because I'm feeling lazy at the moment.

code:
require 'socket'

socket = TCPServer.new('127.0.0.1', 2000)
loop { Thread.start(server.accept) { |session| session.print "Hello world\n" } }

Author:  wtd [ Wed Nov 23, 2005 8:14 pm ]
Post subject: 

Create two classes "Foo" and "Bar". They should both implement "baz" and "put_baz" methods. The "baz" method should return a string. The "put_baz" method should print that string.

You may use the "def" keyword only three times and the class keyword only twice, and Foo and Bar may not share a common base class, other than Object.

Author:  Cervantes [ Wed Nov 23, 2005 9:15 pm ]
Post subject: 

Ruby:

module Bazzy
        def baz
                "Bazzy!"
        end
        def put_baz
                puts baz
        end
end

class Foo
        include Bazzy
end

class Bar
        include Bazzy
end

Foo.new.put_baz
Bar.new.put_baz

Author:  wtd [ Wed Nov 23, 2005 9:21 pm ]
Post subject:  Re: Ruby TYS

wtd wrote:
Let's kick it off with a challenge.

Given a file containing dates in the format:

code:
092203
072105
061704


That is read into an array called 'dates'.

code:
["092203", "072105", "061704"]


Create a new array called 'new_dates' with each date in the format: mm/dd/yy, rather than mmddyy.

Don't use regular expressions or slices. Smile


The answer:

code:
new_dates = dates.collect { |date| date.unpack("A2A2A2").join("/") }

Author:  wtd [ Tue Nov 29, 2005 5:53 pm ]
Post subject: 

code:
irb(main):006:0> class String
irb(main):007:1>   
irb(main):008:2>     
irb(main):009:2>   
irb(main):010:1> end
=> nil
irb(main):011:0> "hello"
=> *****


Fill in the missing code. Smile

Note that with "hello" we get five stars. If one input "foo" on the next line, the result should be three stars.

Author:  wtd [ Thu Dec 01, 2005 7:18 pm ]
Post subject: 

code:
irb(main):001:0> a = Array.new(4, [])
=> [[], [], [], []]
irb(main):002:0> a[0] << 4
=> [4]
irb(main):003:0> a
=> [[4], [4], [4], [4]]


Rewrite the first line of code such that the third line yields:

code:
[[4], [], [], []]


You may only remove one character, and add two others.

Author:  wtd [ Mon Dec 05, 2005 1:23 pm ]
Post subject: 

wtd wrote:
code:
irb(main):006:0> class String
irb(main):007:1>    def inspect
irb(main):008:2>       '*' * length 
irb(main):009:2>    end
irb(main):010:1> end
=> nil
irb(main):011:0> "hello"
=> *****


Fill in the missing code. Smile

Note that with "hello" we get five stars. If one input "foo" on the next line, the result should be three stars.


Smile

Author:  wtd [ Mon Dec 05, 2005 1:24 pm ]
Post subject: 

wtd wrote:
code:
irb(main):001:0> a = Array.new(4, [])
=> [[], [], [], []]
irb(main):002:0> a[0] << 4
=> [4]
irb(main):003:0> a
=> [[4], [4], [4], [4]]


Rewrite the first line of code such that the third line yields:

code:
[[4], [], [], []]


You may only remove one character, and add two others.


code:
irb(main):001:0> a = Array.new(4) { [] }
=> [[], [], [], []]
irb(main):002:0> a[0] << 4
=> [4]
irb(main):003:0> a
=> [[4], [], [], []]

Author:  wtd [ Tue Dec 20, 2005 12:06 am ]
Post subject: 

With using "if", "or", "?" or "unless"...

Create a very simple "Stack" class which holds elements internally in an instance variable "@elements" of type Array. The class must only have a working "push" method. It must not include code outside of the definition of the "push" method, including other methods.

Author:  Cervantes [ Wed Dec 21, 2005 9:47 pm ]
Post subject: 

code:

class Stack
        def push( *values )
                @elements = [] unless @elments   # unless @elements is not empty
                @elements.push( *values )
        end
end

Author:  wtd [ Wed Dec 21, 2005 9:55 pm ]
Post subject: 

Cervantes wrote:
code:

class Stack
        def push( *values )
                @elements = [] unless @elments   # unless @elements is not empty
                @elements.push( *values )
        end
end


Good. Streamlined.

code:
class Stack
   def push(*values)
      @elements ||= []
      @elements.push(*values)
   end
end

Author:  wtd [ Sun Dec 25, 2005 3:00 pm ]
Post subject: 

Add a reverse! method to the module Enumerable. It should be defined in terms of inject. The method may not contain any code other than a call to inject. You are not allowed to define "helper methods". The assignment operator may not occur in the code.

Author:  wtd [ Wed Dec 28, 2005 3:03 am ]
Post subject: 

A demonstration.

The following, which was the answer to a previous question, may be reduced by an additional line.

code:
class Stack
   def push(*values)
      @elements ||= []
      @elements.push(*values)
   end
end


Can become:

code:
class Stack
   def push(*values)
      (@elements ||= []).push(*values)
   end
end


How is this possible?

It's possible because:

code:
@elements ||= []


Is not simply a statement. It is an expression. An expression which happens to return @elements.

In reality, the code in its original form is probably better, but it's important to realize that the code demonstrated here is possible and Ruby is quite happy to work with it.

Author:  Cervantes [ Wed Dec 28, 2005 10:35 pm ]
Post subject: 

Mm mmm!

It's the same reason you can do things like:
code:

a = b = 5

First, we look at the right side: b = 5. b is set to 5, and (b = 5) returns 5, so a = (b = 5), which is a = 5, so both a and b equal 5.

Hurray! Cool

Author:  Cervantes [ Fri Jan 13, 2006 5:27 pm ]
Post subject: 

The first non-wtd TYS (to the best of my knowledge)!

Given a String object, a:
code:

a = "Hello World"

Call the upcase, index, and sub methods on a, to the same effect as this:
code:

a.upcase
a.index( 'l' )
a.sub( 'o', 'u' )


Do this with one line, and you may use a maximum of two dots (".") or double-colons ("::").

You may print the output of method calls if you like.


edit: wtd has solved the problem, within 6 minutes. Just as "Chuck Norris once ate three 72 oz. steaks in one hour. He spent the first 45 minutes having sex with his waitress.", wtd spent most of this time away from the computer. Perhaps wtd is in fact Chuck Norris. Shockingly, I've just discovered evidence that suggests wtd is actually Chuck Norris, but has changed his name sort of like an anagram.

The TYS is still open to all non-Chuck Norris'.

Author:  rdrake [ Fri Jan 27, 2006 6:19 pm ]
Post subject: 

Cervantes wrote:
The first non-wtd TYS (to the best of my knowledge)!

Given a String object, a:
code:

a = "Hello World"

Call the upcase, index, and sub methods on a, to the same effect as this:
code:

a.upcase
a.index( 'l' )
a.sub( 'o', 'u' )


Do this with one line, and you may use a maximum of two dots (".") or double-colons ("::").

You may print the output of method calls if you like.
Here's the solution:
code:
[[:sub, "o", "u"], :upcase, [:index, "l"]].each do |message| p a.send(*message) end

Author:  Cervantes [ Sat Feb 11, 2006 12:42 pm ]
Post subject: 

Good, cartoon_shark!

Next:
We can use attr_reader to, in effect, give read access to instance variables, like this:
code:

class Foo
    attr_reader :bar
    def initialize(bar)
        @bar = bar
    end
end

puts Foo.new(42).bar


However, this only works with instance variables. Trying to use this with a class variable produces a NoMethodError when trying to read the value.
code:

irb(main):001:0> class Foo
irb(main):002:1>   attr_reader :bar
irb(main):003:1>   def Foo.set_bar(value)
irb(main):004:2>     @@bar = value
irb(main):005:2>   end
irb(main):006:1> end
=> nil
irb(main):007:0> Foo.set_bar(42)
=> 42
irb(main):008:0> Foo.bar
NoMethodError: undefined method `bar' for Foo:Class
        from (irb):8
        from :0


Write code that makes the following possible:
code:

class Foo
    class_attr_reader :bar, :baz
    def Foo.set_bar(value)
        @@bar = value
    end
    def Foo.set_baz(value)
        @@baz = value
    end
end

class Bar
    class_attr_reader :foo
    def Bar.set_foo(value)
        @@foo = value
    end
end

Foo.set_bar("Pizza for dinner tonight, wtd.  ;-)")
Foo.set_baz("Onion, red pepper, sausage, diced tomato, and two kinds of cheese.")
Bar.set_foo("And most importantly, green olives!  Mmmm!")

puts Foo.bar
puts Foo.baz
puts Bar.foo

Foo and Bar may contain only the code shown above. (They may not be re-opened.)

Edit: Solved, by wtd. 20 minutes. Beast! Once again, the TYS will remain open for a while.

Author:  rdrake [ Sun Feb 12, 2006 12:34 am ]
Post subject: 

Not an easy one at all. I'll send you the solution when you're on IRC later, mostly likely tomorrow.

Anybody else care to try this one out for themselves?

Author:  wtd [ Tue Feb 14, 2006 2:54 pm ]
Post subject: 

As a follow-up to Cervantes' TYS, create a conditional_attr_writer method such that I can write, for example:

code:
conditional_attr_writer :foo => lambda { |self, new_val| new_val > self.foo }.
                        :bar => lambda { |self, new_val| new_val > 3 }

Author:  Cervantes [ Tue Feb 14, 2006 8:06 pm ]
Post subject: 

Nice one, wtd. Smile

Although, I had to change "self" in the lambda function to "current".

Cervantes' Answer wrote:


class Module
def conditional_attr_writer(hsh)
hsh.each_pair { |hsh_key, hsh_value|
class_eval %Q[
@@#{hsh_key}_condition = hsh_value
def #{hsh_key}=(new_val)
@#{hsh_key} = new_val if @@#{hsh_key}_condition.call(@#{hsh_key}, new_val)
end
]
}
end
end

class Bar
conditional_attr_writer :foo => lambda { |current, new_val| new_val > current },
:bar => lambda { |current, new_val| new_val > 3 }
attr_reader :foo, :bar

def initialize
@foo = 42
@bar = 7
end

end
a = Bar.new
a.foo = 42
p a.foo
a.bar = 6
p a.bar
a.bar = 2
p a.bar



And to cartoon_shark, Good job, once again! Hikaru79, you've got some catching up to do. Wink

Edit: Dammit! It's either white text, or no indented code. Spoiler tags would be great.
Edit^2: Dammit! /me removes a single, useless line of code

Author:  wtd [ Tue Feb 14, 2006 8:49 pm ]
Post subject: 

Excellent

Author:  wtd [ Sat May 13, 2006 5:49 pm ]
Post subject: 

New TYS.

Does Ruby have a case ("switch" in some languages) statement?

Author:  Cervantes [ Sat May 13, 2006 7:16 pm ]
Post subject: 

wtd wrote:
Does Ruby have a case ("switch" in some languages) statement?

No. Trick question: Ruby has a case expression.

Author:  wtd [ Sun May 14, 2006 7:10 am ]
Post subject: 

Cervantes wrote:
wtd wrote:
Does Ruby have a case ("switch" in some languages) statement?

No. Trick question: Ruby has a case expression.


Indeed.

Author:  Cervantes [ Sat May 20, 2006 12:27 pm ]
Post subject: 

There's quite a few Ruby TYS questions over at Freerange right now. I'll copy the questions only to here.
Cervantes wrote:
Let's start off with a fairly easy one.

code:
irb(main):001:0> true | puts("or")
or
=> true

Explain why "or" is output, despite the fact that the '|' operator should know the whole expression is true after seeing the initial 'true', since true or something is true.


Cervantes wrote:
This next TYS is tough, I think, but it's worth it. It's quite fun. Smile

In one line of code, write a program that computes the factorial of a given number. I say it in this manner because I'm not asking you to write a function. Indeed, there is to be no use of "def" or "while" or "loop" any other looping structure.

I'm being kind of vague about this because otherwise I'll give too much away. Feel free to post answers; if it's not what I'm looking for, I'll let you know.

Addendum: I want a recursive solution. But keep in mind, you can't define any methods!


Cervantes wrote:
In one line (no semi-colon cheating, of course), write a program that loops infinitely. It should not crash due to a stack overflow (ie. we're not using recursion, here). You may not use any keywords.


For discussion and answers, please visit the Freerange Ruby TYS thread.

Author:  zylum [ Thu Jun 01, 2006 11:07 am ]
Post subject: 

Ruby:
puts (1..ARV[0].to_i).inject{|p,n|p*n}

Author:  Cervantes [ Thu Jun 01, 2006 3:28 pm ]
Post subject: 

zylum wrote:
Ruby:
puts (1..ARV[0].to_i).inject{|p,n|p*n}


Since when has zylum been doing Ruby? Smile

That's essentially the solution wtd posted on the Freerange forums, which prompted me to add that addendum: I want a recursive solution.

In any case, the answers to all these are found in the Freerange TYS thread.

Here's two more:
Cervantes wrote:

Quit a standard IRB session. You cannot use any irb methods such as (exit, quit, irb_exit, irb_quit...). Things like Ctrl+D and Ctrl+Z do not count. IRB should not exit because of any error. The code you write into IRB that makes it exit must be valid Ruby code.

Cervantes wrote:
Write a short amount of code that makes the following possible:
code:
p Rubidium.new

output wrote:
#<Rubidium:0xb7cf9ed0>

(Of course, the 0xb7cf9ed0 will change.)
The code should apply generally; that is, we're not writing an empty Rubidium class, here.

Author:  zylum [ Thu Jun 01, 2006 6:13 pm ]
Post subject: 

Cervantes wrote:
Since when has zylum been doing Ruby? Smile


since two days ago Smile

Author:  wtd [ Thu Jun 01, 2006 7:09 pm ]
Post subject: 

zylum wrote:
Cervantes wrote:
Since when has zylum been doing Ruby? Smile


since two days ago Smile


<Mr. Burns> Excellent... </Mr. Burns>


: