2

Suppose I have:

Book = Struct.new(:title, :content)
book = Book.new('harry potter', 'a bunch of content here')
p book.title #=> harry potter

What I want the last line to produce is "Harry Potter". I know I can do something like:

Book = Struct.new(:title, :content) do
  def capitalized_title
    self.title.gsub(/\S+/, &:capitalize)
  end
end

and then call capitalized_title, but what I want is to not have to create a separate method, instead, have some way of when you assign "title" to a new Book object, the title is immediately capitalized. Some kind of hook method, I would guess.

2 Answers 2

5
class Book < Struct.new(:title, :content)
  def title
    super.gsub(/\S+/, &:capitalize)
  end
end

book = Book.new('harry potter', 'a bunch of content here')
book.title # => "Harry Potter"

Book = Struct.new(:title, :content) do
  alias orig_title title
  def title
    orig_title.gsub(/\S+/, &:capitalize)
  end
end

To prevent title is called every time, override title=:

Book = Struct.new(:title, :content) do
  alias orig_title= title=
  def initialize(*args)
    super
    self.title = title
  end
  def title= value
    self.orig_title = value.gsub(/\S+/, &:capitalize)
  end
end
Sign up to request clarification or add additional context in comments.

2 Comments

Question in your first answer, is the super.gsub line invoked every time book.title is called?
@Anthony, You're right. I update the answer to include another code which does not call gsub every time.
2

You could create an initialize method for the class Book (borrowing @falsetru's nice way of capitalizing the the words in title). First note that Book does not have its own initialize method;;

Book = Struct.new(:title, :content)
  #=> Book
Book.private_instance_methods(false)
  #=> []

Rather, it inherits from Struct:

Book.private_instance_methods.include?(:initialize)
  #=> true   
Book.instance_method(:initialize).owner
  #=> Struct
Struct.private_instance_methods(false)
  #=> [:initialize, :initialize_copy]

We add an initialize method in the usual way:

Book = Struct.new(:title, :content) do
  def initialize(title,content)
    self.title = title.gsub(/\S+/, &:capitalize)
    self.content = content
  end
end

confirm:

Book.private_instance_methods(false)
  #=> [:initialize]

and test:

book = Book.new('harry potter', 'a bunch of content here')
book.title
  #=> "Harry Potter"
book.content
  #=> "a bunch of content here"

If there were more than just two instance variables, we might do this:

Book = Struct.new(:title, :content) do
  def initialize(title,content)
    super
    self.title = title.gsub(/\S+/, &:capitalize)
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.