# Beginner help needed: use a class def to create new instance

**URL:** <https://www.ruby-forum.com/t/beginner-help-needed-use-a-class-def-to-create-new-instance/192256>\
**Category:** Ruby\
**Created:** [July 27, 2010, 6:36am UTC](https://www.ruby-forum.com/t/beginner-help-needed-use-a-class-def-to-create-new-instance/192256 "2010-07-27T06:36:07Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![studlee2](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/278dde/32.png) [@studlee2](https://www.ruby-forum.com/u/studlee2)\
**Post date:** [July 27, 2010, 6:36am UTC](https://www.ruby-forum.com/t/beginner-help-needed-use-a-class-def-to-create-new-instance/192256/1 "2010-07-27T06:36:07Z")

</div>

I am attempting to put as much code inside classes as possible, to  
economize the code in the main body. However, how do I create a new  
class instance using only a method defined in a class?

For instance, in the following code, I want to create a new Class  
Character instance named newchar by fleshing out the code in the #'d  
area. Is it possible?

Otherwise, what is best practice?

PS: I realize I can instantiate newchar=Character.new(da da da) from the  
body of the code but that would require the prompting code be there  
also. that would defeat my purpose. I hope I have given this enough  
thought before posting! 🙂

Best Regards  
Steve.

#!/usr/bin/ruby -w

class Character  
attr\_reader :chname, :chnick, :chquote  
def initialize(chname,chnick)  
@chname=chname  
@chnick=chnick  
@chquote=String.new  
end  
def addquote(quote)  
@chquote=quote if quote.length \> 10  
end  
def promptedinput  
print "Char name: ";chname=gets.chomp  
print "Char Nick: ";chnick=gets.chomp  
print "Char Quote: ";chquote=gets.chomp  
# Need help here!  
# What code goes here to add Character class instance?  
# class instance name should be newchar  
end  
end

puts newchar.inspect #referencing added instance.

**END**

---

<div class="post-metadata">

**Author:** ![studlee2](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/278dde/32.png) [@studlee2](https://www.ruby-forum.com/u/studlee2)\
**Post date:** [July 27, 2010, 8:48am UTC](https://www.ruby-forum.com/t/beginner-help-needed-use-a-class-def-to-create-new-instance/192256/2 "2010-07-27T08:48:36Z")

</div>

On Tue, Jul 27, 2010 at 6:36 AM, Steve P. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> PS: I realize I can instantiate newchar=Character.new(da da da) from the  
> body of the code but that would require the prompting code be there  
> also. that would defeat my purpose. I hope I have given this enough  
> thought before posting! 🙂

Two considerations:

- I tend to separate the domain objects from the code that interacts  
with the outside world to gather the data to populate that domain  
object (user typing, DB, etc). This way you gain flexibility, being  
able to add ways of loading or creating the object without modifying  
that class

- If, in any case, you want the interaction with the user in that  
class, I would use a class method that returns an instance. If you  
have other ways of creating that instance you can add new methods for  
each case. For example:

#!/usr/bin/ruby -w

class Character  
attr\_reader :chname, :chnick, :chquote  
def initialize(chname,chnick)  
@chname=chname  
@chnick=chnick  
@chquote=String.new  
end  
def addquote(quote)  
@chquote=quote if quote.length \> 10  
end  
def self.from\_prompted\_input  
print "Char name: ";chname=gets.chomp  
print "Char Nick: ";chnick=gets.chomp  
print "Char Quote: ";chquote=gets.chomp  
Character.new chname, chnick,chquote  
end  
end

puts Character.from\_prompted\_input.inspect

What you had in mind couldn’t work, because your method was an  
instance method, so from the outside you still needed someone to call  
Character.new(x,y,z).promptedinput.

Having class methods to instantiate objects of the class in different  
ways is a pretty typical idiom, check for example the Date class in  
core:

[http://ruby-doc.org/core/classes/Date.html](http://ruby-doc.org/core/classes/Date.html)

The methods civil, commercial, etc are class methods that return an  
instance, constructed in a different way.

Jesus.

---

<div class="post-metadata">

**Author:** ![studlee2](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/278dde/32.png) [@studlee2](https://www.ruby-forum.com/u/studlee2)\
**Post date:** [July 31, 2010, 1:59am UTC](https://www.ruby-forum.com/t/beginner-help-needed-use-a-class-def-to-create-new-instance/192256/3 "2010-07-31T01:59:16Z")

</div>

JesÃºs Gabriel y GalÃ¡n,

I was able to accomplish (at least crudely) moving code from the main  
body to the class. I felt this was worth doing because I want as much  
logic as possible in the class. (Is this a worthy thing??)

As you advised, I was able to create my new instance using a method that  
returned an object.

Could you please take a look at how I implemented these two methods?  
Account.setupaccount, Account.report

Is this how you would have structured it?  
Any tips or comments greatly appreciated.  
Steve.

#!/usr/bin/ruby  
class Account  
attr\_reader :nbr, :name, :coa  
def initialize(nbr,name,coa)  
@nbr=nbr  
@name=name  
setcoa(coa)  
end  
def setcoa(coa)  
if [“income”, “expense”, “asset”, “liability”,  
“capital”].include?(coa) then  
@coa=coa  
else  
puts “Error, defaulted to expense”  
@coa=“expense”  
end  
end  
def Account.setupaccount  
#data entry routine inside class, not in main code body.  
print "enter acct nbr: ";nbr=gets.chomp  
print "enter name: ";name=gets.chomp  
print "enter presen: ";coa=gets.chomp  
return Account.new(nbr,name,coa)  
end  
def Account.report(acct)  
#reporting code inside class, not in main body.  
puts “===Account Number Listing===”  
puts “Account Nbr: #{acct.nbr}”  
puts “Account Name: #{acct.name}”  
puts “Account CofA: #{acct.coa}”  
end  
end  
##Start of main code body ##  
newacct=Account.setupaccount  
Account.report(newacct)  
##End of Main code body ##

When I clear my confusion about this, I will do something like  
class Ledger \< Account  
##code to make an array of the Account objects and add more  
functionality  
end

JesÃºs Gabriel y GalÃ¡n wrote:

> On Tue, Jul 27, 2010 at 6:36 AM, Steve P. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
> wrote:
> 
> > PS: I realize I can instantiate newchar=Character.new(da da da) from the  
> > body of the code but that would require the prompting code be there  
> > also. that would defeat my purpose. I hope I have given this enough  
> > thought before posting! 🙂
> 
> Two considerations:
> 
> - I tend to separate the domain objects from the code that interacts  
> with the outside world to gather the data to populate that domain  
> object (user typing, DB, etc). This way you gain flexibility, being  
> able to add ways of loading or creating the object without modifying  
> that class
> 
> - If, in any case, you want the interaction with the user in that  
> class, I would use a class method that returns an instance. If you  
> have other ways of creating that instance you can add new methods for  
> each case. For example:
> 
> #!/usr/bin/ruby -w
> 
> class Character  
> attr\_reader :chname, :chnick, :chquote  
> def initialize(chname,chnick)  
> ï¿½ @chname=chname  
> ï¿½ ï¿½ @chnick=chnick  
> ï¿½ ï¿½ @chquote=String.new  
> end  
> ï¿½ def addquote(quote)  
> ï¿½ @chquote=quote if quote.length \> 10  
> ï¿½ end  
> ï¿½ def self.from\_prompted\_input  
> ï¿½ ï¿½ print “Char name: ï¿½ ï¿½”;chname=gets.chomp  
> ï¿½ ï¿½ print “Char Nick: ï¿½ ï¿½”;chnick=gets.chomp  
> ï¿½ ï¿½ print “Char Quote: ï¿½ ï¿½ ï¿½ ï¿½ ï¿½”;chquote=gets.chomp  
> Character.new chname, chnick,chquote  
> end  
> end
> 
> puts Character.from\_prompted\_input.inspect
> 
> What you had in mind couldn’t work, because your method was an  
> instance method, so from the outside you still needed someone to call  
> Character.new(x,y,z).promptedinput.
> 
> Having class methods to instantiate objects of the class in different  
> ways is a pretty typical idiom, check for example the Date class in  
> core:
> 
> [http://ruby-doc.org/core/classes/Date.html](http://ruby-doc.org/core/classes/Date.html)
> 
> The methods civil, commercial, etc are class methods that return an  
> instance, constructed in a different way.
> 
> Jesus.

---

<div class="post-metadata">

**Author:** ![studlee2](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/278dde/32.png) [@studlee2](https://www.ruby-forum.com/u/studlee2)\
**Post date:** [July 31, 2010, 11:00am UTC](https://www.ruby-forum.com/t/beginner-help-needed-use-a-class-def-to-create-new-instance/192256/4 "2010-07-31T11:00:40Z")

</div>

On Sat, Jul 31, 2010 at 2:06 AM, Steve P. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Account.setupaccount, Account.report  
> @name=name  
> end  
> Maybe call this coa=, as it’s a setter?

def coa=(coa)  
…  
end

> def Account.setupaccount

def Account.setup\_account is more idiomatic. Also I usually do def  
self.setup\_account, but that’s a matter of taste, I guess.

> puts “Account Name: #{acct.name}”  
> puts “Account CofA: #{acct.coa}”  
> end  
> end  
> ##Start of main code body ##  
> newacct=Account.setupaccount  
> Account.report(newacct)  
> ##End of Main code body ##

As I said, I don’t really like having the user interaction inside the  
domain class. For reporting, specially, I would create a to\_s method  
that formats the account info, and then have the caller of that method  
be the one writing to stdout or to a file or whatever:

def to\_s  
s=\<\<EOF  
===Account Number Listing===  
Account Nbr: #{acct.nbr}  
Account Name: #{acct.name}  
Account CofA: #{acct.coa}  
EOF  
s  
end

> When I clear my confusion about this, I will do something like  
> class Ledger \< Account  
> ##code to make an array of the Account objects and add more  
> functionality  
> end

If you want an array of Account objects, you shouldn’t inherit from  
Account, but rather have an instance variable that holds an array of  
Accounts:

class Ledger

def initialize  
@accounts = []  
end  
…  
end

Jesus.

---

<div class="post-metadata">

**Author:** ![studlee2](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/278dde/32.png) [@studlee2](https://www.ruby-forum.com/u/studlee2)\
**Post date:** [August 1, 2010, 1:30pm UTC](https://www.ruby-forum.com/t/beginner-help-needed-use-a-class-def-to-create-new-instance/192256/5 "2010-08-01T13:30:42Z")

</div>

Steve P. wrote:

> class Character  
> attr\_reader :chname, :chnick, :chquote  
> def initialize(chname,chnick)  
> @chname=chname  
> @chnick=chnick  
> @chquote=String.new  
> end  
> def addquote(quote)  
> @chquote=quote if quote.length \> 10  
> end  
> def promptedinput  
> print "Char name: ";chname=gets.chomp  
> print "Char Nick: ";chnick=gets.chomp  
> print "Char Quote: ";chquote=gets.chomp  
> # Need help here!  
> # What code goes here to add Character class instance?  
> # class instance name should be newchar  
> end  
> end

I think you want a class method, not an instance method, since you’re  
creating a new object which doesn’t have any relation to any existing  
object.

class Character  
def initialize(chname,chnick,chquote="")  
@chname=chname  
@chnick=chnick  
@chquote=chquote  
end  
def self.promptedinput  
print "Char name: ";chname=gets.chomp  
print "Char Nick: ";chnick=gets.chomp  
print "Char Quote: ";chquote=gets.chomp  
new(chnam,chnick,chquote)  
end  
end

newchar = Character.promptedinput  
puts newchar.inspect

Note that I modified your initialize method to accept chquote as an  
optional third argument. If you don’t want to do that, then::

def self.promptedinput  
print "Char name: ";chname=gets.chomp  
print "Char Nick: ";chnick=gets.chomp  
print "Char Quote: ";chquote=gets.chomp  
result = new(chname,chnick)  
result.chquote = chquote  
result  
end
