Attributes not populated until called?

Hello all,

Pretty much new to Ruby, and I think I am not grasping something fundamental
here. I've written some classes that grab meta tags from various audio file
formats, and overrode 'to_s" to dump the tags to the console, and "to_a" to
dump the tags to an array for use elsewhere in my program.

I am not sure how to explain my problem, so I will just paste in a session
from irb that shows it:

require 'sneetchalizer' # my class definitions...
x =OggMetaTags.new('/home/music/e/elliottSmith-shootingStar.ogg')

=> #<OggMetaTags:0xa7cc1ac8 [...rest omitted...]

x.to_a

=> ["", "", "", "", "", "", ""]

x.title

=> "Shooting Star"

x.to_a

=> ["Shooting Star", "", "", "", "", "", ""]

x.artist

=> "Elliott Smith"

x.to_a

=> ["Shooting Star", "Elliott Smith", "", "", "", "", ""]

So you can see I need to explicitly call each attribute before my array gets
the value. How can I change this so the array is populated automatically when
called?

Here is the class:

class OggMetaTags < MetaTags
  def initialize(filename)
    @filename = filename
    require 'ogginfo'
    @tags = OggInfo.new(@filename)
  end
  def title
    @title = @tags.tag['title']
  end
  def artist
    @artist = @tags.tag['artist']
  end
  def album
    @album = @tags.tag['album']
  end
  def genre
    @genre = @tags.tag['genre']
  end
  def year
    @year = @tags.tag['date']
  end
  def comment
    @comment = super
  end
  def tracknum
    @tracknum = @tags.tag['tracknumber']
  end

  def to_a
    ["#@title", "#@artist", "#@album", "#@genre", "#@year", "#@comment",
"#@tracknum"]
  end
end

If you need more info or want to see all the code please just ask. Thanks for
consideration,
-d

···

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972

Hello all,

Pretty much new to Ruby, and I think I am not grasping something
fundamental
here. I've written some classes that grab meta tags from various audio
file
formats, and overrode 'to_s" to dump the tags to the console, and "to_a"
to
dump the tags to an array for use elsewhere in my program.

I am not sure how to explain my problem, so I will just paste in a session
from irb that shows it:

> require 'sneetchalizer' # my class definitions...
> x =OggMetaTags.new('/home/music/e/elliottSmith-shootingStar.ogg')

All instance variables are defaulting to nil, none of the instance variables
set in the initializer, are used in to_a, so to_a converts nil to a string
which happens to be an empty string.

=> #<OggMetaTags:0xa7cc1ac8 [...rest omitted...]

> x.to_a
=> ["", "", "", "", "", "", ""]
> x.title

=> "Shooting Star"

The title method sets the instance variable @title, therefore to_a yields
...

x.to_a
=> ["Shooting Star", "", "", "", "", "", ""]

idem

x.artist
=> "Elliott Smith"
> x.to_a
=> ["Shooting Star", "Elliott Smith", "", "", "", "", ""]

So you can see I need to explicitly call each attribute before my array
gets
the value. How can I change this so the array is populated automatically
when
called?

Here is the class:

class OggMetaTags < MetaTags
  def initialize(filename)
    @filename = filename
    require 'ogginfo'
    @tags = OggInfo.new(@filename)
  end
  def title
    @title = @tags.tag['title']
  end
  def artist
    @artist = @tags.tag['artist']
  end
  def album
    @album = @tags.tag['album']
  end
  def genre
    @genre = @tags.tag['genre']
  end
  def year
    @year = @tags.tag['date']
  end
  def comment
    @comment = super
  end
  def tracknum
    @tracknum = @tags.tag['tracknumber']
  end

  def to_a
    ["#@title", "#@artist", "#@album", "#@genre", "#@year", "#@comment",
"#@tracknum"]
  end
end

If you need more info or want to see all the code please just ask. Thanks
for
consideration,

No the programmatic behavior is clear, I fail to see the reason though, but
there might be one.
As a matter of fact there is a good reason to cache the value of the
attribute in the reader but that would be done like this
@year = @tags.tag['date']

-d

···

On 6/6/06, darren kirby <bulliver@badcomputer.org> wrote:

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more
expected..."
- Dennis Ritchie and Ken Thompson, June 1972

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

darren kirby wrote:

Hello all,

So you can see I need to explicitly call each attribute before my array gets the value. How can I change this so the array is populated automatically when called?

Add code to to_a to populate the instance variables if they are not et assigned, or have the initializer assign the instance variables when an object is created.

Calling a method will only do what the method code is set up to do.

···

--
James Britt

"Blanket statements are over-rated"

ATTRIBUTES = %w( title artist album genre year comment )

   def to_a
     ATTRIBUTES.map{|a| send a}
   end

you are using un-initialized instance vars - your methods are lazy
initializers, you need to use them here.

-a

···

On Wed, 7 Jun 2006, darren kirby wrote:

def to_a
   ["#@title", "#@artist", "#@album", "#@genre", "#@year", "#@comment",
"#@tracknum"]
end
end

--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

>
> Hello all,
>
> Pretty much new to Ruby, and I think I am not grasping something
> fundamental
> here. I've written some classes that grab meta tags from various audio
> file
> formats, and overrode 'to_s" to dump the tags to the console, and "to_a"
> to
> dump the tags to an array for use elsewhere in my program.
>
> I am not sure how to explain my problem, so I will just paste in a
> session
> from irb that shows it:
>
> > require 'sneetchalizer' # my class definitions...
> > x =OggMetaTags.new('/home/music/e/elliottSmith-shootingStar.ogg')

All instance variables are defaulting to nil, none of the instance
variables set in the initializer, are used in to_a, so to_a converts nil to
a string which happens to be an empty string.

=> #<OggMetaTags:0xa7cc1ac8 [...rest omitted...]
> > x.to_a
> => ["", "", "", "", "", "", ""]
> > x.title

=> "Shooting Star"

The title method sets the instance variable @title, therefore to_a
yields ...

> x.to_a
> => ["Shooting Star", "", "", "", "", "", ""]

idem

> x.artist
> => "Elliott Smith"
> > x.to_a
> => ["Shooting Star", "Elliott Smith", "", "", "", "", ""]
>
> So you can see I need to explicitly call each attribute before my array
> gets
> the value. How can I change this so the array is populated automatically
> when
> called?

Here is the class:
>
> class OggMetaTags < MetaTags
> def initialize(filename)
> @filename = filename
> require 'ogginfo'
> @tags = OggInfo.new(@filename)
> end
> def title
> @title = @tags.tag ['title']
> end
> def artist
> @artist = @tags.tag['artist']
> end
> def album
> @album = @tags.tag['album']
> end
> def genre
> @genre = @tags.tag['genre']
> end
> def year
> @year = @ tags.tag['date']
> end
> def comment
> @comment = super
> end
> def tracknum
> @tracknum = @tags.tag['tracknumber']
> end
>
> def to_a
> ["#@title", "#@artist", "#@album", "#@genre", "#@year", "#@comment",
>
> "#@tracknum"]
> end
> end
>
> If you need more info or want to see all the code please just ask.
> Thanks for
> consideration,

No the programmatic behavior is clear, I fail to see the reason though,
but there might be one.
As a matter of fact there is a good reason to cache the value of the
attribute in the reader but that would be done like this

Sorry slipped from a key, continuing...

@year ||= @tags.tag['date']

which will access the hash only once.

Hope that helped
Robert

-d

···

On 6/6/06, Robert Dober <robert.dober@gmail.com> wrote:

On 6/6/06, darren kirby <bulliver@badcomputer.org> wrote:
> --
> darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
> "...the number of UNIX installations has grown to 10, with more
> expected..."
> - Dennis Ritchie and Ken Thompson, June 1972
>

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

quoth the James Britt:

darren kirby wrote:
> Hello all,
>
> So you can see I need to explicitly call each attribute before my array
> gets the value. How can I change this so the array is populated
> automatically when called?

Add code to to_a to populate the instance variables if they are not et
assigned, or have the initializer assign the instance variables when an
object is created.

Ok, so I changed the code so the assignments are in initialize(). Now I am
getting some broken behavior. First of all, most of the tags are getting set
by the super class which is only supposed to happen if the tag is 'comment':

x = OggMetaTags.new('/home/music/e/elliottSmith-shootingStar.ogg')

=> #<OggMetaTags etc etc

x.to_a

=> ["/home/music/e/elliottSmith-shootingStar",
"/home/music/e/elliottSmith-shootingStar", "unknown", "unknown", "unknown",
"unknown", "12"]

So here the only tag set correctly is the tracknumber "12". The rest were set
by the super class except for 'comment' which is supposed to be 'Starbellied
using sneetchalizer' but is instead 'unknown'?! I am completely lost as to
what is going on here.

I suppose I better list the super class as well:

class MetaTags
  attr_reader :title, :artist, :album, :genre, :year, :comment, :tracknum
  def initialize(filename)
    @filename = filename
    @title = @filename[0..-5]
    @artist = @title
    @album = 'unknown'
    @genre = 'unknown'
    @year = 'unknown'
    @comment = 'Starbellied using sneetchalizer'
    @tracknum = 'unknown'
  end
  def to_s
    puts "Title: #@title"
    puts "Artist: #@artist"
    puts "Album: #@album"
    puts "Genre: #@genre"
    puts "Year: #@year"
    puts "Comment: #@comment"
    puts "Tracknum: #@tracknum"
  end
  def to_a
    ["#@title", "#@artist", "#@album", "#@genre", "#@year", "#@comment",
"#@tracknum"]
  end
end

class OggMetaTags < MetaTags
  attr_reader :title, :artist, :album, :genre, :year, :comment, :tracknum
  def initialize(filename)
    @filename = filename
    require 'ogginfo'
    @tags = OggInfo.new(@filename)
    @title = @tags.tag['title']
    @artist = @tags.tag['artist']
    @album = @tags.tag['album']
    @genre = @tags.tag['genre']
    @year = @tags.tag['date']
    @comment = super
    @tracknum ||= @tags.tag['tracknumber']
  end
end

Calling a method will only do what the method code is set up to do.

Understood! About the only thing I understand now...

Thanks for the responses guys,
-d

···

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972

quoth the ara.t.howard@noaa.gov:

> def to_a
> ["#@title", "#@artist", "#@album", "#@genre", "#@year", "#@comment",
> "#@tracknum"]
> end
> end

   ATTRIBUTES = %w( title artist album genre year comment )

   def to_a
     ATTRIBUTES.map{|a| send a}
   end

Thank you!
This worked perfectly...

you are using un-initialized instance vars - your methods are lazy
initializers, you need to use them here.

-a

Thanks again,
-d

···

On Wed, 7 Jun 2006, darren kirby wrote:

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972

quoth the Robert Dober:
<snip>

>
> No the programmatic behavior is clear, I fail to see the reason though,
> but there might be one.
> As a matter of fact there is a good reason to cache the value of the
> attribute in the reader but that would be done like this

Sorry slipped from a key, continuing...

@year ||= @tags.tag['date']

which will access the hash only once.

I tried this and it is giving me the default tags (from the super class)
rather than using 'ogginfo'?! So is putting them in initialize() (see my
response to James Britt...

Hope that helped
Robert

-d

> > --
> > darren kirby :: Part of the problem since 1976 ::
> > http://badcomputer.org "...the number of UNIX installations has grown
> > to 10, with more expected..."
> > - Dennis Ritchie and Ken Thompson, June 1972
>
> --
> Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
> concerne l'univers, je n'en ai pas acquis la certitude absolue.
>
> - Albert Einstein

-d

···

On 6/6/06, Robert Dober <robert.dober@gmail.com> wrote:

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972

Ok, so I changed the code so the assignments are in
initialize(). Now I am
getting some broken behavior. First of all, most of the tags
are getting set
by the super class which is only supposed to happen if the
tag is 'comment':

...

    @comment = super

That line calls the initialize() method from your superclass and assigns
the result of that method (coming from the last line "@tracknum =
'unknown'") to the @comment variable.

What you probably want is:

module TagDisplayer
  ATTRIBUTES = %w{title artist album genre year comment tracknum}
  attr_reader *ATTRIBUTES
  def to_a
     ATTRIBUTES.map {|x| send(x)}
  end
  def to_s
     ATTRIBUTES.map {|x| "#{x.capitalize}: #{send(x)}"
}.join("\n")
  end
end

class MetaTags
  include TagDisplayer
  def initialize(filename)
    @filename = filename
    @title = @filename[0..-5]
    @artist = @title
    @album = 'unknown'
    @genre = 'unknown'
    @year = 'unknown'
    @comment = 'Starbellied using sneetchalizer'
    @tracknum = 'unknown'
  end
end

class OggMetaTags < MetaTags
  include TagDisplayer
  def initialize(filename)
    @filename = filename
    require 'ogginfo'
    @tags = OggInfo.new(@filename)
    @title = @tags.tag['title']
    @artist = @tags.tag['artist']
    @album = @tags.tag['album']
    @genre = @tags.tag['genre']
    @year = @tags.tag['date']
    @comment = 'Starbellied using sneetchalizer'
    @tracknum = @tags.tag['tracknumber']
  end
end

quoth the Robert Dober:
<snip>
> >
> > No the programmatic behavior is clear, I fail to see the reason
though,
> > but there might be one.
> > As a matter of fact there is a good reason to cache the value of the
> > attribute in the reader but that would be done like this
>
> Sorry slipped from a key, continuing...
>
> @year ||= @tags.tag['date']
>
> which will access the hash only once.

I tried this and it is giving me the default tags (from the super class)
rather than using 'ogginfo'?! So is putting them in initialize() (see my
response to James Britt...

That is strange, you mean @year is not initialized when calling to_a, but it
is when
calling the accessor method first?

Anyway that might not be what you are interested in, the caching mechanism
is maybe not
what you wanted either, I was just guessing about semantics :wink:

Cheers
Robert

···

On 6/6/06, darren kirby <bulliver@badcomputer.org> wrote:

> On 6/6/06, Robert Dober <robert.dober@gmail.com> wrote:

Hope that helped
> Robert
>
> -d
>
> > > --
> > > darren kirby :: Part of the problem since 1976 ::
> > > http://badcomputer.org "...the number of UNIX installations has
grown
> > > to 10, with more expected..."
> > > - Dennis Ritchie and Ken Thompson, June 1972
> >
> > --
> > Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
> > concerne l'univers, je n'en ai pas acquis la certitude absolue.
> >
> > - Albert Einstein

-d
--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more
expected..."
- Dennis Ritchie and Ken Thompson, June 1972

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

add a call to super in your subclass initialize to get the defaults from
the superclass

Then only assign to attributes where the values differ from the defaults

Cheers
Chris

···

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

quoth the Daniel Sheppard:

> Ok, so I changed the code so the assignments are in
> initialize(). Now I am
> getting some broken behavior. First of all, most of the tags
> are getting set
> by the super class which is only supposed to happen if the
> tag is 'comment':

...

> @comment = super

That line calls the initialize() method from your superclass and assigns
the result of that method (coming from the last line "@tracknum =
'unknown'") to the @comment variable.

Why does it do this? I thought it would run the 'comment' method in the
superclass. That is what I was trying to do anyway. In the bigger picture, I
have this:

MetaTags
    OggMetaTags
    Mp3MetaTags
    M4aMetaTags

I have a little wrapper function that checks the filetype you pass to it, then
dispatches the appropriate tag handling class to return the tags for use. If
the file is not an ogg, m4a, or mp3 then the defaults should be created using
MetaTags. I am trying to make this as transparent as possible. ie: you pass
it a filename, and it returns an array of tags, doing the right thing
internally.

What you probably want is:

Can you define a module in the same file as where you call it? I am not sure
why you would do it this way instead of simply adding to_a and to_s in
MetaTags? Can you explain why you suggest to do it this way? Please remember
I am just learning Ruby and I do appreciate a bit of explainaition so I might
learn some good style..

module TagDisplayer
  ATTRIBUTES = %w{title artist album genre year comment tracknum}
  attr_reader *ATTRIBUTES
  def to_a
     ATTRIBUTES.map {|x| send(x)}
  end
  def to_s
     ATTRIBUTES.map {|x| "#{x.capitalize}: #{send(x)}"
}.join("\n")
  end
end

class MetaTags
  include TagDisplayer
  def initialize(filename)
    @filename = filename
    @title = @filename[0..-5]
    @artist = @title
    @album = 'unknown'
    @genre = 'unknown'
    @year = 'unknown'
    @comment = 'Starbellied using sneetchalizer'
    @tracknum = 'unknown'
  end
end

class OggMetaTags < MetaTags
  include TagDisplayer
  def initialize(filename)
    @filename = filename
    require 'ogginfo'
    @tags = OggInfo.new(@filename)
    @title = @tags.tag['title']
    @artist = @tags.tag['artist']
    @album = @tags.tag['album']
    @genre = @tags.tag['genre']
    @year = @tags.tag['date']
    @comment = 'Starbellied using sneetchalizer'
    @tracknum = @tags.tag['tracknumber']
  end
end

Thanks for the help Daniel, and everybody else. It is appreciated.
-d

···

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972

quoth the Robert Dober:

> quoth the Robert Dober:
>
> <snip>
>
> > > No the programmatic behavior is clear, I fail to see the reason
>
> though,
>
> > > but there might be one.
> > > As a matter of fact there is a good reason to cache the value of the
> > > attribute in the reader but that would be done like this
> >
> > Sorry slipped from a key, continuing...
> >
> > @year ||= @tags.tag['date']
> >
> >
> > which will access the hash only once.
>
> I tried this and it is giving me the default tags (from the super class)
> rather than using 'ogginfo'?! So is putting them in initialize() (see my
> response to James Britt...

That is strange, you mean @year is not initialized when calling to_a, but
it is when
calling the accessor method first?

Well, that is what I was seeing before. After trying your code it is getting
set to 'unknown' which is what the super class assigns to @year...

···

On 6/6/06, darren kirby <bulliver@badcomputer.org> wrote:
> > On 6/6/06, Robert Dober <robert.dober@gmail.com> wrote:

Anyway that might not be what you are interested in, the caching mechanism
is maybe not
what you wanted either, I was just guessing about semantics :wink:

Cheers
Robert

> Hope that helped
>
> > Robert
> >
> > -d
> >
> > > > --
> > > > darren kirby :: Part of the problem since 1976 ::
> > > > http://badcomputer.org "...the number of UNIX installations has
>
> grown
>
> > > > to 10, with more expected..."
> > > > - Dennis Ritchie and Ken Thompson, June 1972
> > >
> > > --
> > > Deux choses sont infinies : l'univers et la bêtise humaine ; en ce
> > > qui concerne l'univers, je n'en ai pas acquis la certitude absolue.
> > >
> > > - Albert Einstein
>
> -d
> --
> darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
> "...the number of UNIX installations has grown to 10, with more
> expected..."
> - Dennis Ritchie and Ken Thompson, June 1972

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972