consider the following example
module DataMapper
class Property
class CustomType < DataMapper::Property::Text
def load(value)
# do stuff and return formatted value
end
end
end
end
Class A
property :name, String
property :value, CustomType
end
now when I do A.first or A.first.value the load method gets executed, but the calculations that I need to do inside load is dependent on that instance's name property. So how do I get the context of this instance/resource(as referred inside source code) inside the load method ?
Please let me know if the question is not clear yet !
You are attempting to break encapsulation. The name and value are different properties, and thus each should be in ignorance of the other's existence, let alone value.
The correct solution is to move the "stuff" to an object which has visibility over both properties. The two options are:
the A class (as suggested by user1376019); or
a complex data type, e.g. NameAndValue < DataMapper::Property::Object, which encapsulates both properties.
If you need to perform aggregate functions over the individual properties, the second option would not work, unless you can somehow override the complex property to have multiple fields.
In either case, value cannot refer to name without a reference to it.
Related
I have a method that returns an object which could be one of many different types of object but which are all part of the same ancestor class. The precise object type is inferred dynamically.
However, I'm confused as to what to put for the return value in the signature. I've put a placeholder below using instance_of to illustrate the problem:
sig{params(instance_class: String).returns(instance_of ParentClass)}
def build_instance instance_class
klass = Object.const_get(instance_class)
return klass.new
end
Given that I don't know which precise class will be returned (and I'd prefer not to list them explicitly) but I do know that it will be a subclass of ParentClass is there a way in Sorbet to specify this? I could use T.untyped but it's unnecessarily loose.
Through trial and error I've discovered that checking that the object includes the type in its ancestors is, if I understand correctly, sorbet's default behaviour.
Sorbet won't check that the object precisely matches the specified Type, only that it includes that type in its ancestors (perhaps this is what Typechecking in general means but I'm fairly new to the game).
To avoid the following error though:
Returning value that does not conform to method result type https://srb.help/7005
you also need to T.cast() the object that you return to the ParentClass:
sig{params(instance_class: String).returns(ParentClass)}
def build_instance instance_class
klass = Object.const_get(instance_class)
# NB instance is a descendent of ParentClass, not an instance...
return T.cast(klass.new, ParentClass)
end
This seems to work but I'd love to know whether it's the correct way to solve the problem.
As a little hobby project, I'm trying to build up my own object system. I was wondering if there is a way of changing the default inheritance of all classes from Object to my base class Entity, so that whenever I create a new class I don't have to explicitly say class Thing < Entity; ideally, I would just be able to say class Thing and have its default superclass be my Entity class.
Sure you could do this by modifying the relevant part of the Ruby source and recompiling Ruby:
VALUE
rb_define_class_id(ID id, VALUE super)
{
VALUE klass;
if (!super) super = rb_cObject; // <-- where the default is set
klass = rb_class_new(super);
// ...
But that’s a huge hassle and requires patching and running a custom Ruby and probably has a lot of gotchas and things that are hard-coded to assume Object is the default.
And, on top of that, what’s the point? If you replace Object with something else as the default superclass, every class—including those in Ruby core—will now inherit from this new default superclass. You could get the same effect (just without the different name) far more easily and without needing a custom Ruby by just changing Object itself. That’s the beauty of being able to reopen classes! For example:
class Object
def foo
'bar!'
end
end
class A; end
A.new.foo #=> 'bar!'
If you wanted to be kind you might even just put all the relevant methods in an Entity module instead of a class and then include it into Object.
No, unfortunately this is not possible in Ruby. Ruby does not have a Meta-Object Protocol like e.g. CLOS that would allow you to manipulate the core semantics of the Object Model. It would be nice, though!
I have been a Java programmer for a while and I am trying to switch to ruby for a while. I was just trying to develop a small test program in ruby and my intention is something like following.
I want to create a simple linked list type of an object in ruby; where an instance variable in class points to another instance of same type.
I want to populate and link all nodes; before the constructor is called and only once. Something that we'd usually do in Java Static block.
Initialize method is a constructor signature in ruby. Are there any rules around them? Like in Java you cannot call another constructor from a constructor if its not the first line (or after calling the class code?)
Thanks for the help.
-Priyank
I want to create a simple linked list type of an object in ruby; where an instance variable in class points to another instance of same type.
Just a quick note: the word type is a very dangerous word in Ruby, especially if you come from Java. Due to an historic accident, the word is used both in dynamic typing and in static typing to mean two only superficially related, but very different things.
In dynamic typing, a type is a label that gets attached to a value (not a reference).
Also, in Ruby the concept of type is much broader than in Java. In Java programmer's minds, "type" means the same thing as "class" (although that's not true, since Interfaces and primitives are also types). In Ruby, "type" means "what can I do with it".
Example: in Java, when I say something is of type String, I mean it is a direct instance of the String class. In Ruby, when I say something is of type String, I mean it is either
a direct instance of the String class or
an instance of a subclass of the String class or
an object which responds to the #to_str method or
an object which behaves indistinguishably from a String.
I want to populate and link all nodes; before the constructor is called and only once. Something that we'd usually do in Java Static block.
In Ruby, everything is executable. In particular, there is no such thing as a "class declaration": a class body is just exectuable code, just like any other. If you have a list of method definitions in your class body, those are not declarations that are read by the compiler and then turned into a class object. Those are expressions that get executed by the evaluator one by one.
So, you can put any code you like into a class body, and that code will be evaluated when the class is created. Within the context of a class body, self is bound to the class (remember, classes are just objects like any other).
Initialize method is a constructor signature in ruby. Are there any rules around them? Like in Java you cannot call another constructor from a constructor if its not the first line (or after calling the class code?)
Ruby doesn't have constructors. Constructors are just factory methods (with stupid restrictions); there is no reason to have them in a well-designed language, if you can just use a (more powerful) factory method instead.
Object construction in Ruby works like this: object construction is split into two phases, allocation and initialization. Allocation is done by a public class method called allocate, which is defined as an instance method of class Class and is generally never overriden. It just allocates the memory space for the object and sets up a few pointers, however, the object is not really usable at this point.
That's where the initializer comes in: it is an instance method called initialize, which sets up the object's internal state and brings it into a consistent, fully defined state which can be used by other objects.
So, in order to fully create a new object, what you need to do is this:
x = X.allocate
x.initialize
[Note: Objective-C programmers may recognize this.]
However, because it is too easy to forget to call initialize and as a general rule an object should be fully valid after construction, there is a convenience factory method called Class#new, which does all that work for you and looks something like this:
class Class
def new(*args, &block)
obj = alloc
obj.initialize(*args, &block)
return obj
end
end
[Note: actually, initialize is private, so reflection has to be used to circumvent the access restrictions like this: obj.send(:initialize, *args, &block)]
That, by the way, is the reason why to construct an object you call a public class method Foo.new but you implement a private instance method Foo#initialize, which seems to trip up a lot of newcomers.
To answer your question: since an initializer method is just a method like any other, there are absolutely no restrictions as to what you can do whithin an initializer, in particular you can call super whenever, wherever, however and how often you want.
BTW: since initialize and new are just normal methods, there is no reason why they need to be called initialize and new. That's only a convention, although a pretty strong one, since it is embodied in the core library. In your case, you want to write a collection class, and it is quite customary for a collection class to offer an alternative factory method called [], so that I can call List[1, 2, 3] instead of List.new(1, 2, 3).
Just as a side note: one obvious advantage of using normal methods for object construction is that you can construct instances of anonymous classes. This is not possible in Java, for absolutely no sensible reason whatsoever. The only reason why it doesn't work is that the constructor has the same name as the class, and anonymous classes don't have a name, ergo there cannot be a constructor.
Although I am not quite sure why you would need to run anything before object creation. Unless I am missing something, shouldn't a list basically be
class List
def initialize(head=nil, *tail)
#head = head
#tail = List.new(*tail) unless tail.empty?
end
end
for a Lisp-style cons-list or
class List
def initialize(*elems)
elems.map! {|el| Element.new(el)}
elems.zip(elems.drop(1)) {|prv, nxt| prv.instance_variable_set(:#next, nxt)}
#head = elems.first
end
class Element
def initialize(this)
#this = this
end
end
end
for a simple linked list?
You can simply initialize your class variables in the class body, outside of any method declaration. It will behave like a static initializer in Java:
class Klass
##foo = "bar"
def sayFoo
puts ##foo
end
def self.sayFoo
puts ##foo
end
end
The class field ##foo is here initialized to "bar".
In ruby object creation works like this
class Class
def new(*args)
obj= self.allocate # get some memory
obj.send(:initialize) # call the private method initialize
end
end
Object#initialize is just an ordinary private method.
If you wan't something to happen before Object#initialize you have to write your own Class#new. But I see no reason why you would want to do that.
This is basically the same answer paradigmatic gave back in '09.
Here I want to illustrate that the "static initializer" can call other code. I'm simulating a scenario of loading a special user once, upon class initialization.
class Foo
def user
"Thomas"
end
end
class Bar
##my_user = Foo.new.user
def my_statically_defined_user
##my_user
end
end
b = Bar.new
puts b.my_statically_defined_user # ==> Thomas
I'm having trouble creating a new model row in the database using ActiveRecord in a Sinatra app I'm developing. The object in question is being created without any errors (using save!, no exceptions are raised), but most of the data I specify for the save is not present.
class ProjectMeta < ActiveRecord::Base
attr_accessor :completion_ratio, :num_stories, :num_completed_stories, :original_target_date, :current_target_date
...
def self.create_from_project(project)
meta = ProjectMeta.new
meta.project_id = project.id
meta.num_stories = project.num_stories
meta.num_completed_stories = project.num_completed_stories
meta.completion_ratio = ProjectMeta.calculate_ratio(project.num_completed_stories, project.num_stories)
meta.current_target_date = project.current_target_date
meta.save!
meta
end
...
end
All inspections on the data from the project object I'm sending as well as the new meta object I'm creating show that the data is present. But when I do a meta.inspect before and after the save, it shows that all the data (aside from project_id) is in it's default state (zeroes). I've also checked meta.errors.nil? and sure enough, there aren't any errors after the save.
What is most puzzling is that if I turn around and get a new meta instance with that project_id and put the data in, it saves no problem to the db.
This is frustrating me because I've built several sites in Rails and Sinatra with ActiveRecord. This one issue is completely perplexing me. Can anyone tell me what I'm doing wrong?
Here is how it works
On first access to model, columns from corresponding database table are retrieved and stored inside model data. This information can be retrieved through ::columns class method.
When you access some model's attribute, Ruby doesn't find corresponding method in class and launches #method_missing method. That method inspects model's ::columns to check if corresponding column exists. If so, it creates an accessors for that column so that next time you access that model's attribute, an accessor method will be called directly, without need to call #method_missing (the later is slower).
The accessors look like this:
def my_attribute
read_attribute(:my_attribute)
end
def my_attribute=(value)
write_attribute(:my_attribute, value)
end
For #read_attribute and #write_attribute methods there is a shortcut: #[] and #[]=. If for some reason you will need to access underlying data directly (e.g. do some data conversion), you can write them short:
def my_attribute
self[:my_attribute]
end
def my_attribute=(value)
self[:my_attribute] = value
end
Model has a special accessor -- #attributes -- which returns a "column_name => value" Hash.
NOTE: the data for each column is stored in a special Hash instance inside your model instance, not in "#column_name" instance variables. When you define accessors with #attr_accessor, you block the usual way of defining attribute accessors via #method_missing. Your data is stored in instance variables instead of "attributes" hash, so it is not saved into database.
If you want to add new attribute to your model, you actually need to add column to database table that correspond to that model and then reload the whole application.
There's an important distinction between database fields and temporary attr_accessor declared properties. If you've declared your columns, then attr_accessor declarations are unnecessary.
Keep in mind that the data should be stored in the model's attributes property to be properly saved, not as individual instance variables.
For example, to see what's scheduled to be saved:
class MyModel < ActiveRecord::Base
attr_accessor :not_saved
end
model = MyModel.new(:not_saved => 'foo')
puts model.attributes.inspect
There are methods to get information on what columns are available in a model, such as:
MyModel.columns_names
The attr_accessors will never be saved to the DB. These are internal variables within the instance. If you want to save the values, you have to create real columns.
Make a migration to declare the columns then try again.
I have a curiosity question. If I have a ruby class and then I dynamically add class methods, class variables, etc. to it during execution is there anyway for me to save the altered class definition so that next time I start my application I can use it again?
There is no built-in way to do this. Marshal can't save methods. If these methods and variables are generated in some systematic way, you could save the data necessary for the class to recreate them. For example, if you have a make_special_method(purpose, value) method that defines these methods, create an array of the arguments you need to pass to these methods and read it in when you want to reconstitute the state of the class.
Depending on what exactly you mean, there are a couple of ways to go about this.
The simplest case is the one where you've added variables or methods to an already-existing class, as in this example:
class String
def rot13
return self.tr('a-z', 'n-za-m')
end
end
Here we've added the rot13 method to class String. As soon as this code is run, every String everywhere in your program will be able to #rot13. Thus, if you have some code that needs rot13-capable strings, you just ensure that the code above is run before the code in question, e.g. by putting the rot13 code in a file someplace and require()ing it. Very easy!
But maybe you've added a class variable to a class, and you want to preserve not just its existence but its value, as in:
class String
##number_of_tr_calls_made = 0
# Fix up #tr so that it increments ##number_of_tr_calls_made
end
Now if you want to save the value of ##number_of_tr_calls_made, you can do so in the same way you would with any other serializable Ruby value: via the Marshal library. Also easy!
But something in the way you phrased your question makes me suspect that you're doing something like this:
greeting = "Hello"
class <<greeting
def rot13
return self.tr('a-z', 'n-za-m')
end
end
encrypted_greeting = greeting.rot13
This is very different from what we did in the first example. That piece of code gave every String in your program the power to rot13 itself. This code grants that power to only the object referred to by the name 'greeting'. Internally, Ruby does this by creating an anonymous Singleton subclass of String, adding the rot13 method to it, and changing greeting's class to that anonymous subclass.
The problem here is that Singletons can't be Marshal'd (to see why, try to figure out how to maintain the Singleton invariant when any call to Marshal.load can generate copies of extant Singleton objects). Now greeting has a Singleton in its inheritance hierarchy, so if you want to save and load it you are hosed. Make a subclass instead:
class HighlySecurableString < String
def rot13
return self.tr('a-z', 'n-za-m')
end
end
greeting = HighlySecurableString.new("hello")
Simply marshalling the object (as others have said) wont work. Lets look at an example. Consider this class:
class Extras
attr_accessor :contents
def test
puts "This instance of Extras is OK. Contents is: " + #contents.to_s
end
def add_method( name )
self.class.send :define_method, name.to_sym do
puts "Called " + name.to_s
end
end
end
Now lets write a program which creates an instance, adds a method to it and saves it to disk:
require 'extras'
fresh = Extras.new
fresh.contents = 314
fresh.test # outputs "This instance of Extras is OK. Contents is: 314"
fresh.add_method( :foo )
fresh.foo # outputs "Called foo"
serial = Marshal.dump( fresh )
file = File.new "dumpedExample", 'w'
file.write serial
So we can call the normal method 'test' and the dynamic method 'foo'. Lets look at what happens if we write a program which loads the instance of Example which was saved to disk:
require 'extras'
file = File.new 'dumpedExample', 'r'
serial = file.read
reheated = Marshal.load( serial )
reheated.test # outputs "This instance of Extras is OK. Contents is 314"
reheated.foo # throws a NoMethodError exception
So we can see that while the instance (including the values of member variables) was saved the dynamic method was not.
From a design point of view it's probably better to put all your added code into a module and load that into the class again when you next run the program. We'd need a good example of how you might want to use it though to really know this.
If you need extra information to recreate the methods then have the module save these as member variables. Implement included in the module and have it look for these member variables when it is included into the class.
http://ruby-doc.org/core/classes/Marshal.html
You're editing the class on the fly, and you want to save that? You could try using the Marshal module, it'll allow you to save objects to a file, and read them back in memory dynamically.