[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Attribute writers

Michael Judge

1/6/2006 9:17:00 AM

I'm working on a survey system in Ruby and am having a style crisis with
a simple bit of code that has left me paralyzed and unable to work.

Respondent data in research surveys is traditionally stored as big
strings of text like this: "123145992348241110111 11 11 1 1111 3331 1"

This was a made up example, in the real world however, there's sometimes
hundreds of thousands of characters in each respondent's data string.
In the stats and analysis section of my program, I'm working out how to
access subsets of these strings in an object-oriented way.

Something like this appeals to me and is very readable:

if currentRespondent.ascii(0..2) == 123
currentRespondent.ascii(0..2) = 777
end

How would one actually implement this?

class Respondent
def ascii(range)
return @ascii[range]
end

# doesn't work
def ascii(range)=(value)
@ascii[range] = value
end
end

currentRespondent = Respondent.new

This is broken code, as Ruby doesn't like me trying to do "def
a(b)=(c)". There's other ways to accomplish the same purpose (e.g. def
setter(range,value)) but I'm obsessed with the attribute writer form --
which is just so dang cool.

Anyone have some light they could spare?

Argh. I've been struggling with this for a week!

--
Posted via http://www.ruby-....


4 Answers

Ross Bamford

1/6/2006 9:52:00 AM

0

On Fri, 06 Jan 2006 09:16:50 -0000, Michael Judge
<mjudge@surveycomplete.com> wrote:

> I'm working on a survey system in Ruby and am having a style crisis with
> a simple bit of code that has left me paralyzed and unable to work.
>
> Respondent data in research surveys is traditionally stored as big
> strings of text like this: "123145992348241110111 11 11 1 1111 3331 1"
>
> This was a made up example, in the real world however, there's sometimes
> hundreds of thousands of characters in each respondent's data string.
> In the stats and analysis section of my program, I'm working out how to
> access subsets of these strings in an object-oriented way.
>
> Something like this appeals to me and is very readable:
>
> if currentRespondent.ascii(0..2) == 123
> currentRespondent.ascii(0..2) = 777
> end
>
> How would one actually implement this?
>

Is this any help?

irb(main):006:0> s = "123145992348241110111 11 11 1 1111 3331 1"
=> "123145992348241110111 11 11 1 1111 3331 1"
irb(main):007:0> s[0..2]
=> "123"
irb(main):008:0> s[0..2] = '777'
=> "777"
irb(main):009:0> s
=> "777145992348241110111 11 11 1 1111 3331 1"

> class Respondent
> def ascii(range)
> return @ascii[range]
> end
>
> # doesn't work
> def ascii(range)=(value)
> @ascii[range] = value
> end
> end
>
> currentRespondent = Respondent.new
>
> This is broken code, as Ruby doesn't like me trying to do "def
> a(b)=(c)". There's other ways to accomplish the same purpose (e.g. def
> setter(range,value)) but I'm obsessed with the attribute writer form --
> which is just so dang cool.
>
> Anyone have some light they could spare?
>
> Argh. I've been struggling with this for a week!
>

As far as I'm aware you can't do indexed attribute writers. You can of
course do:

def []=(idx, val)
puts "at #{idx} = #{val}"
end

But Ruby won't have it if you prefix the [] with a name.

What I think I'd do is just remove the writer (for this purpose) and have
ascii return a String. The you can do:

if currentRespondent[0..2] == '777'
currentRespondent.ascii[0..2] = "123"
end

(since String's [] is pretty flexible as I showed above)

But I have a feeling I may have missed something in your question. Is that
helpful?

--
Ross Bamford - rosco@roscopeco.remove.co.uk

Hal E. Fulton

1/6/2006 9:57:00 AM

0

Michael Judge wrote:
> I'm working on a survey system in Ruby and am having a style crisis with
> a simple bit of code that has left me paralyzed and unable to work.
>
> Respondent data in research surveys is traditionally stored as big
> strings of text like this: "123145992348241110111 11 11 1 1111 3331 1"
>
> This was a made up example, in the real world however, there's sometimes
> hundreds of thousands of characters in each respondent's data string.
> In the stats and analysis section of my program, I'm working out how to
> access subsets of these strings in an object-oriented way.
>
> Something like this appeals to me and is very readable:
>
> if currentRespondent.ascii(0..2) == 123
> currentRespondent.ascii(0..2) = 777
> end
>
> How would one actually implement this?

I'd suggest doing a little metaprogramming and making the final code
a little easier.

Here is a very rough outline -- if you like it I can help flesh out
the details:


class Respondent

Fields = { :this => 0..2,
:that => 3..6,
:etc => 7..10 }

Fields.each_pair do |field,range|
# add a reader basically doing @resp[range]
# add a writer basically doing @resp[range]=val
end

def initialize(str)
@resp = str
end

end


resp = Respondent.new(whatever)
if resp.this == Something
resp.this = SomethingElse
end
do_whatever if resp.that != resp.this


Make sense?

Hal



Hal E. Fulton

1/6/2006 10:10:00 AM

0

Michael Judge wrote:
> I'm working on a survey system in Ruby and am having a style crisis with
> a simple bit of code that has left me paralyzed and unable to work.

Here is the rest of my solution.

Does this help?


Hal


class Respondent

Fields = { :this => 0..2,
:that => 3..6,
:etc => 7..10 }

Fields.each_pair do |field,range|
# add a reader basically doing @resp[range]
define_method(field) { @resp[range] }
# add a writer basically doing @resp[range]=val
define_method((field.to_s+"=").to_sym) do |val|
raise "Wrong field length" if val.size != range.to_a.size
@resp[range] = val
end
end

def initialize(str)
@resp = str
end

end


resp = Respondent.new("abcdefghij")

puts resp.this
puts resp.that
puts resp.etc

resp.that = "foob"

puts resp.this
puts resp.that
puts resp.etc

resp.that = "foo" # error!



Robert Klemme

1/6/2006 10:28:00 AM

0

Michael Judge wrote:
> I'm working on a survey system in Ruby and am having a style crisis
> with a simple bit of code that has left me paralyzed and unable to
> work.
>
> Respondent data in research surveys is traditionally stored as big
> strings of text like this: "123145992348241110111 11 11 1 1111 3331
> 1"
>
> This was a made up example, in the real world however, there's
> sometimes hundreds of thousands of characters in each respondent's
> data string. In the stats and analysis section of my program, I'm
> working out how to access subsets of these strings in an
> object-oriented way.
>
> Something like this appeals to me and is very readable:
>
> if currentRespondent.ascii(0..2) == 123
> currentRespondent.ascii(0..2) = 777
> end
>
> How would one actually implement this?
>
> class Respondent
> def ascii(range)
> return @ascii[range]
> end
>
> # doesn't work
> def ascii(range)=(value)
> @ascii[range] = value
> end
> end
>
> currentRespondent = Respondent.new
>
> This is broken code, as Ruby doesn't like me trying to do "def
> a(b)=(c)". There's other ways to accomplish the same purpose (e.g.
> def setter(range,value)) but I'm obsessed with the attribute writer
> form -- which is just so dang cool.
>
> Anyone have some light they could spare?
>
> Argh. I've been struggling with this for a week!

Hm, I wouldn't use a string internally at all - at least not if you are
trying to do it OO. This is what I'd do:

class Results
include Enumerable

def initialize(from_string = "")
@fields = from_string.split(/\s+/).map {|s| s.to_i}
end

def field() @fields end

def each(&b)
@fields.each(&b)
self
end

def size() @fields.size end
def empty?() @fields.empty? end

def to_str
@fields.map {|d| d.to_s}.join ' '
end

alias :to_s :to_str

def to_a() @fields end
end

You could also simply subclass Array and create appropriate constructors
and to_s, to_str methods:

class Results < Array
def initialize(from_string = "")
super( from_string.split(/\s+/).map! {|s| s.to_i} )
end

def to_str
map {|d| d.to_s}.join ' '
end

alias :to_s :to_str
end

HTH

Kind regards

robert