3 ms·
Your question is more in regards to Ruby itself, and not Rails. You don't have to swap out implementations in Ruby. Implementations aside, when you do DI in Ja
by dutchrapley 15y ago
Your question is more in regards to Ruby itself, and not Rails. You don't have to swap out implementations in Ruby.
Implementations aside, when you do DI in Java, it serves two purposes: 1) instantiates an object and 2) wires it into another object. Remember that in Java, each class is in it's own file. In ruby, you can break classes into several files, but you don't have to. Ruby simply reads class declarations at runtime and instantiates those classes into constants. This means that your classes are always available. If you've defined a class method, you can call SomeClass.some_class_method. If you want to work with an instance of that class, you would call SomeClass.new - to which you can pass args to a constructor.
In your instance, you could have three classes - User, UserLdap, and UserDb. You might call User.find( person ), and in the find method you would test your conditional on whether to use UserLdap or UserDb. If you had common methods you wanted to share between the two, you could place those in User and extend that class for use with an instance object. Another option for sharing methods cold be to place them in a module, which you can then include in your class.
It's hard for me the make a recommendation for your specific problem at hand. My best advice is to read up and Ruby a little and begin to put what you learn into practice. Here's a couple of recommendations:
http://www.humblelittlerubybook.com/ http://www.humblelittlerubybook.com/
http://mislav.uniqpath.com/poignant-guide/ http://mislav.uniqpath.com/poignant-guide/
My light bulb moments were realizing that all class declarations are loaded as constants at runtime and class & instance methods are also managed in the same class declaration. HTH.
- geebee 15y agoThanks for your reply... I'm kind of following you - unfortunately, I don't know ruby well enough to understand what you mean when you say class declarations are loaded as constants at run time, but I'll definitely look into it. I think there's a third purpose to DI that you didn't mention. The container does instantiate an object and inject it ("wire it") into another object, but the real benefit is that you can externally configure which object to swap in. That last part might matter less in a language that doesn't have to be compiled but it can still be valuable if you have a lot of different implementations that need to be swapped in/out in different deployments. The method you described for person - testing a conditional - do you mean you'd create a method with a conditional, and choose which implementation to use based on that conditional? I've done this, and it certainly works, but it isn't really a placement for DI (this sounds more like a factory method, though again I don't think that those really exist to the same extent in ruby since duck typing is much more flexible than static typing). My problem with this approach (if I understand it right, which I'm not sure I do) is that this would lead to a very long series of conditionals to load the right class. In rails, I'd probably be looking to pull them out into a yaml file (something like the applicationContext file in Spring).
- dutchrapley 15y ago"class declarations are loaded as constants at run time" Let's say I create a class called User. When ruby sees that declaration, it creates a constant called User to contain that object. When I create a new instance: user = User.new "User" is a constant whose value is the object/class. "new" is a method that calls the constructor (if one exists) and creates a new instance. The same applies when you call something like: User.find You're not calling find() on an instance, you're calling it on the object that's loaded into the constant "User". The class declaration "class User" is saying User is the name of the class; User is also the constant in which it's stored. It's also what allows you to reopen a class on the fly to extend it with more methods. "I think there's a third purpose to DI that you didn't mention. The container does instantiate an object and inject it ("wire it") into another object, but the real benefit is that you can externally configure which object to swap in." True, but I've never found myself switching objects out on a regular basis. As you mentioned, the conditional approach probably isn't the best. What I'm assuming now is that you're based on your deployment, you might use a different bean factory configuration file? And this works as long as UserLdap and UserDb implement the same interface? That being said, instead of sprinkling conditionals throughout user, you can dynamically assign User initially. User = UserDb OR User = UserLdap and as long as UserDb or UserLdap had a find() method, you could then call User.find Remember, User is now a constant that references the same value as UserDb or UserLdap Does that help clarify?
- geebee 15y agoResponding very late, sorry... It does help clarify this, thanks. It does still leave the problem that you have to specify the "type" in the code and can't swap it out. That said, I think this could probably be handled easily with a yaml file (just specify the class you want to instantiate every time a user is created)? I may try that some time.