Instance Variables in ruby

Dogs have many shared characteristics, like the abilities to wag their tails and drink water from a bowl, but they also have information about them that is variable,

like their breed or their name.

Similarly, when designing an application, your users will have common traits, like the ability to log in and out, but some information will be variable,

like a username or email address. Let’s start by setting up a new User class. You can follow along in either irb or by running a script from the command line.

class User
    # stuff will go here
end

By the end of this lesson, you’ll be able to define a User class that can track its own user information.

Say you wanted to assign a user’s username. You might try something like this.

julia = User.new
julia.username = "coolgirl2000"
# NoMethodError: undefined method `username‘ for #<User:0x007fc6fa034148>

Let’s pause to take a look at that error bit by bit.

  • NoMethodError: If I had to guess, I’d say this likely has something to do with a method not existing.
  • undefined method ‘username‘: Suspicions confirmed. It looks like our code can’t find a ‘username‘ method. That makes sense, we never defined one.

But you weren‘t trying to create a new method! You were thinking about this username like a variable, right?

Ruby has no way of distinguishing between variables and methods in this case, since they both come after the ., so it only supports instance methods.

??What do we do now?! To treat username as a variable, you’re going to need to fake this a bit. Let’s write just enough code to stop this pesky error.

class User
  def username=(value)
  end
end

If you recall, most characters are fair game with methods, including =. In this case, the valueargument stands in place of the value you want to assign to username.

julia.username=("coolgirl2000")
# => "coolgirl2000"

That does the trick… sort of. There’s an awful lot of syntax here, and it’s a bit of a stretch to say this looks anything like the julia.username = “coolgirl2000” we were going for.

Luckily, we can leave off the parentheses since those are optional for methods. These little shortcuts are known as syntactic sugar, since they make writing code with it just a bit sweeter ??. Let’s see how that looks.

julia.username= "coolgirl2001"
# => "coolgirl2001"

Wow, I already feel so much less stressed looking at that. The fact that the = is pressed up againstusername is still bothering me. I can’t stop looking at it.

It’s going to bother me forever if you don’t do something about it. Please, do something about it.

Syntactic sugar to the rescue again. When a method ends with =, Ruby rightfully assumes that you’re creating a method for variable assignment. To make your life sweeter, Ruby lets you put a space before the = so it reads more like typical variable assignment, like so:

julia.username = "coolgirl2002"
# => "coolgirl2002"

??Boom. Check that out. I can sleep easily again. You’ve just successfully created (the start of) asetter method (sometimes called a mutator method).

A setter method is one which sets, or changes, the value of a variable belonging to a particular object.

Alright, let’s check in on your username. If my math is correct, it should be set to “coolgirl2002”right now.

julia.username
# NoMethodError: undefined method `username‘ for #<User:0x007fc6fa034148>

This error again. You’ve seen this one before, but didn’t you already create this instance method?

Let’s go ahead and write the bare minimum amount of code to make this error go away.

class User
  def username=(value)
  end

  def username
  end
end

This is the opposite of a setter method, a getter method. It exists to get the value of a variable belonging to an object. Let’s see if this works.

julia.username
# => nil

There’s no error ??, but it’s also returning nil instead of “coolgirl2002”. You may have already caught on to this…

neither your username nor your username= methods actually do anything.

To make your getter and setter methods start working, you’re going to need to capture theusername values somewhere.

The problem here has to do with scope. How can the values you capture in the username= setter method be accessed in the username getter method?

Much like instance methods, you can also use instance variables. Instance variables are variables that are scoped to the entire class.

This means that once an instance variable is defined, it can be used anywhere in that object.

An instance variable looks just like a regular variable, with one minor difference: it starts with @.

class User
  def username=(value)
    @username = value
  end

  def username
    @username
  end
end

Let’s see if this works before moving on.

julia.username = "coolgirl3000"
# => "coolgirl3000"
julia.username
# => "coolgirl3000"

?? Nice!

The @username instance variable is now available to use by any of the methods inside of a Userobject.

You can go ahead and make other User objects now, and each one will be able to track their own information.

walter = User.new
# => #<User:0x007fc6fa034328>
walter.username = "cooldude17"
# => "cooldude17"
walter.username
# => "cooldude17"

And one last check with Julia to make sure her information is still accurate.

julia.username
# => "coolgirl3000"

Remember when we said that $global_variables weren’t the best solution? This is that best solution.

Very rarely will you need a variable that is available to everything inside your application. Often, you just want it available to one or a few objects.

Let me say that again: You will almost never need to use global variables ever again. If you find yourself using one,

there’s a very good chance it can be done some other way using classes.

Getter and setter methods are used so often in Ruby that there are even more shortcuts you can use to make your life sweeter.

Why type more code than you really need to? Remember, Ruby is optimized for developer happiness.

class User
  attr_reader :username
  attr_writer :username
end

attr_reader and attr_writer (“attr” being shorthand for “attribute”) are two methods that take care of creating getter and setter methods, respectively, for you.

Best of all, you can do this for as many attributes as you’d like. Perhaps you want users to be able to change their usernames, but not their birthdays.

class User
  attr_reader :username, :birthday
  attr_writer :username
end

There’s no need to actually write out all those getter and setter methods yourself anymore!

One thing that confused me at first was the syntax of attr_reader and attr_writer.

It didn’t really look like anything I’d ever seen before, at least not until someone rewrote it for me this way:

attr_reader(:username, :birthday)

These are actually instance methods that are already baked in for you to use.

All you are doing is passing in a Symbol representing the instance variable you’d like to create getter and setter methods for.

Accessors

There’s one last refactor we can do here. It’s pretty common to need both a getter and a setter method for an attribute, so why not define both at once?

That’s exactly what attr_accessordoes.

class User
  attr_accessor :username
end

I know what you’re thinking. Yes, I did just string you along this emotional journey only to end up writing three lines of code.

But think about it: now you know what these three lines of code actually do!

Along the way, you learned about instance variables, some neat syntactic sugar, and getters and setters. Not bad.

Let’s continue with the User example. This is what we’ve got at the moment:

class User
  attr_accessor :username
end

This is useful, but presents a slight issue. We don’t want a user to ever be without a username.

The way things are currently set up, you can easily do something like this:

colt = User.new
# => #<User:0x007fc6fb03ae98>
colt.username
# => nil

Because a User is created without a default username value, Colt is left without a username until he goes in and sets one himself.

??This will not do.

There’s a special instance method you can use to make sure an object is properly set up when it’s created, initialize.

When you create a new object, the first thing Ruby will do is look for thatinitialize method and run it.

This makes is super handy for initial setup (for things like… initializing an object with a username, maybe?).

class User
  attr_accessor :username

  def initialize
    @username = "its_colt_outside"
  end
end

Let’s give this another go.

colt = User.new
# => #<User:0x007fc6fb03ae98 @username="its_colt_outside">
colt.username
# => "its_colt_outside"

??Beautiful.

There’s just one issue with the previous example— we’re hard-coding “its_colt_outside” to be the default username for every single user.

That’s not going to help you much when Orit wants to make an account for herself.

How about passing in the username as an argument right from the start, like a method, when creating the new User object?

orit = User.new("supermom")

To do this, you’ll need to modify your User class so that it can accept arguments. It may be tempting to do something like this:

class User(username)
  # ...
end

But as you’ll quickly encounter, this will throw an error. This is a completely reasonable assumption, though.

Instead, you can include the argument as a part of the initialize method.

A good way to remember this is to keep in mind that initialize takes care of everything related to the initial set-up of an object.

Since the username argument deals with the initial set-up of a username, it belongs to the initialize method.

class User
  attr_accessor :username

  def initialize(username)
    @username = username
  end
end

Now you can initialize a User object with a username right when you create it.

orit = User.new("supermom")
# => #<User:0x007fc6fb03ae98 @username="supermom">
orit.username
# => "supermom"

This also safeguards you from creating a new user without a username.

mike = User.new
# ArgumentError: wrong number of arguments (0 for 1)

If you break apart that error, it shouldn’t be too tough to figure out what the issue is.

  • ArgumentError: This probably has something to do with the arguments passed into thisUser object.
  • wrong number of arguments (0 for 1): Zero arguments were passed in, when theUser class is expecting one.

Errors can seem scary, but often they contain vital information to help fix bugs in your code. Good error messages will tell you exactly where you need to make a fix.

时间: 2024-08-08 17:26:07

Instance Variables in ruby的相关文章

instance variables may not be placed in categories

Avoid Properties in Categories Objective-C分类中是不允许增加成员变量的(Instance variables may not be placed in categories),我们可以通过运行时函数objc_setAssociatedObject 和 objc_getAssociatedObject 来让分类支持保存和获取一些数据,从而支持属性. //EOCPerson+FriendShip.h @interface EOCPerson (FriendS

Caching with Instance Variables 缓存与实例变量

class ApplicationController < ActionController::Base   def current_user      User.find(session[:user_id])   endend 上面那段代码的意思是定义一个current_user的方法,函数的作用是调用User中的find方法传入会话中的user_id从数据库读取当前登录大的用户信息.如果这个方法被多次调用,将会多次访问数据库,可以定义一个实例变量,将第一次调用时候的结果缓存到实例变量中供下次

Local versus Instance Variables

实例变量 实例变量声明在一个类中,但在方法.构造方法和语句块之外: 当一个对象被实例化之后,每个实例变量的值就跟着确定: 实例变量在对象创建的时候创建,在对象被销毁的时候销毁: 实例变量的值应该至少被一个方法.构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息: 实例变量对于类中的方法.构造方法或者语句块是可见的.一般情况下应该把实例变量设为私有.通过使用访问修饰符可以使实例变量对子类可见: 实例变量具有默认值.数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的

Class Methods &amp; Variables

When calling an instance method like withdraw_securely, the syntax generally looks something like this: object.method_being_called(arguments) One would therefore think it’s safe to assume that an instance method is always preceded by a ., which is in

【ruby】ruby基础知识

Install Ruby(安装) For windows you can download Ruby from http://rubyforge.org/frs/?group_id=167 for Linux tryhttp://www.rpmfind.net. Our first program(从此开始) Enter the following into the file, "test.rb". ? 1 puts "Howdy!" At the C: promp

ruby面向对象class

ruby对象是严格封装的:只能通过定义的方法访问其内部状态.方法使用的成员变量在对象外部不能直接访问,不过可以通过getter.setter等访问器方法(accessor),使他们看起来好像是直接访问的. 与对象状态的封装性相反,ruby中的类非常开放.每个ruby程序都可以为现有类添加方法,而且也可以为单个对象添加“单键方法(singleton method)”. 创建类 Classes are created in Ruby with the class keyword:class Poin

《ruby编程语言》笔记 1

赋值: ruby支持并行赋值,即允许在赋值表达式中出现多余一个值和多于一个的变量: x,y=1,2a,b=b,ax,y,z=[1,2,3] (python同样可以正常上面的语句). Methods in Ruby are allowed to return more than one value, and parallel assignmentis helpful in conjunction with such methods. For example:# Define a method to

HeadFIrst Ruby 第二章总结 methods and classes

HeadFIrst Ruby 第二章总结 methods and classes 前言 这一章讲了如何创建自己的 class,并且讲了在用 class 创建 object 的两个要素: instance variables 和 instance methods.和它们需要注意的一些问题. 创建 method 相关 问题1:括号 be or not be? 在 Ruby 中,如果需要创建的 method 包含参数,那么后面应该有“()” ;如果不需要任何参数,则不需要加“()”,在调用函数的时候也

python class metaclass instance

>>> class CObj(object):... pass...>>> dir()['CObj', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']>>> cob = CObj>>> dir()['CObj', '__builtins__', '__doc__', '__loader__', '__name__', '__