Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong><em>TL;DR</em>: No it's not possible ... and long answer, yes it is possible, read the metaprogramming section :)</strong></p> <p>Ruby is a dynamic language, that's why you won't get compile time type warnings/errors as you get in languages like C#. </p> <p>Same as you can't specify a type for a variable, you can't specify a type for <code>attr_accessor</code>. </p> <p>This might sound stupid to you coming from .NET, but in the Ruby community, people kind of expect you to write tests. If you do so, these types of problems will basically vanish. In Ruby on Rails, you should test your models. If you do so, you won't really have any trouble with accidentaly assigning something somewhere wrong.</p> <p>If you're talking about ActiveRecord in Ruby on Rails specifically, assigning a String into an attribute which is defined as an Integer in the database will result in exception being thrown.</p> <p>By the way, according to convention, you shouldn't use <code>CamelCase</code> for attributes, so the correct class definition should be </p> <pre><code>class Person attr_accessor :first_name attr_accessor :last_name attr_accessor :home_address end class Address attr_accessor :address_line1 attr_accessor :city attr_accessor :country end </code></pre> <p>One reason for this is that if you Capitalize the first letter, Ruby will define a constant instead of a variable.</p> <pre><code>number = 1 # regular variable Pi = 3.14159 # constant ... changing will result in a warning, not an error </code></pre> <h2>Metaprogramming hacks</h2> <p>By the way, Ruby also has insanely huge metaprogramming capabilities. You could write your own <code>attr_accessor</code> with a type check, that could be used something like</p> <pre><code>typesafe_accessor :price, Integer </code></pre> <p>with definition <del>something</del> like</p> <pre><code>class Foo # 'static', or better said 'class' method ... def self.typesafe_accessor(name, type) # here we dynamically define accessor methods define_method(name) do # unfortunately you have to add the @ here, so string interpolation comes to help instance_variable_get("@#{name}") end define_method("#{name}=") do |value| # simply check a type and raise an exception if it's not what we want # since this type of Ruby block is a closure, we don't have to store the # 'type' variable, it will 'remember' it's value if value.is_a? type instance_variable_set("@#{name}", value) else raise ArgumentError.new("Invalid Type") end end end # Yes we're actually calling a method here, because class definitions # aren't different from a 'running' code. The only difference is that # the code inside a class definition is executed in the context of the class object, # which means if we were to call 'self' here, it would return Foo typesafe_accessor :foo, Integer end f = Foo.new f.foo = 1 f.foo = "bar" # KaboOoOoOoM an exception thrown here! </code></pre> <p><del>or at least something along these lines :)</del> <strong>This code works!</strong> Ruby allows you to define methods on the fly, which is how <code>attr_accessor</code> works.</p> <p>Also blocks are <em>almost always</em> closures, which means I can do the <code>if value.is_a? type</code> without passing it as a parameter.</p> <p>It's too complicated to explain here when this is true and when it's not. In short, there are different types of blocks</p> <ul> <li><code>Proc</code>, which is created by <code>Proc.new</code></li> <li><code>lambda</code>, which is created by the keyword <code>lambda</code></li> </ul> <p>one of the differences is that calling <code>return</code> in a <code>lambda</code> will only return from the lambda itself, but when you do the same thing from a <code>Proc</code>, the whole method around the block will return, which is used when iterating, e.g.</p> <pre><code>def find(array, something) array.each do |item| # return will return from the whole 'find()' function # we're also comparing 'item' to 'something', because the block passed # to the each method is also a closure return item if item == something end return nil # not necessary, but makes it more readable for explanation purposes end </code></pre> <p>If you're into this kind of stuff, I recommend you check out <a href="http://pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming" rel="noreferrer">PragProg Ruby Metaprogramming screencast</a>. </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload