19 Aug, 2010, Runter wrote in the 41st comment:
Votes: 0
As an aside you can also use lazy initialization in modules. There is a way to do what you want. Its just not very common and a little arcane. And I can't seem to remember it atm. :)
19 Aug, 2010, JohnnyStarr wrote in the 42nd comment:
Votes: 0
Ok, here's something I've been working on. Not too outlandish, but could probably be smoothed out a bit:

class Object
def mixin(m)
include m
@@modules ||= []
@@modules << m
end

def init_mods()
@@modules.each {|m| m.init(self)} if @@modules
end

def c_eval(s)
self.class.instance_eval(s)
end

def i_eval(s)
self.instance_eval(s)
end
end

module Carries
def self.init(base)
base.c_eval "attr_accessor :inventory"
base.i_eval "@inventory = Inventory.new"
end
end

class Inventory
def add(o)
puts "you have added a #{o} to your inventory!"
end
end

# ——————————————————
# Now all you have to write is:

class John
mixin Carries

def initialize()
init_mods()
end
end

j = John.new
j.inventory.add "Blade of Gondor"

#=> you have added a Blade of Gondor to your inventory!


Nice thing, is you can "mixin" modules that also make adjustments to the class.
But you can also use "include" parallel without breaking things. Keep in mind, I'm very new to metaprogramming, so eh.
19 Aug, 2010, Runter wrote in the 43rd comment:
Votes: 0
I would rather just add the line of code to initialize of the class in question.
19 Aug, 2010, JohnnyStarr wrote in the 44th comment:
Votes: 0
Sure, I understand that. But this ties together the entire component.
Also, if later on you add more dependencies to a compenent, you do not have to touch the classes.
19 Aug, 2010, Runter wrote in the 45th comment:
Votes: 0
attr_accessor doesn't need to be done each time an obj it initialized.
19 Aug, 2010, JohnnyStarr wrote in the 46th comment:
Votes: 0
? I agree, and I don't know why you brought that up?

Are you talking about the module's init() method?
The only way to call attr_accessor in a module, is by using the base class_eval() or instance_evall()
19 Aug, 2010, Tyche wrote in the 47th comment:
Votes: 0
JohnnyStarr said:
What's weird about this, is that the inventory object initializes as shown, however, it seems that the inventory object
itself is still nil. Anyone know why? I realize that this is in a way multiple-inheritance, but it seems
that in Ruby that isn't so much of a bad thing.


It's much simpler…
class Inventory
def initialize(s)
add_item(s)
end

def add_item(i)
puts "you have added a #{i} to your inventory."
end
end

module Carries
attr_accessor :inventory
def initialize
@inventory = Inventory.new("Blade of Gondor")
end
end

class Player; include Carries; end

p = Player.new
puts p.inventory

#OUTPUT:
# => you have added a Blade of Gondor to your inventory.
# => #<Inventory:0x7fd42d88>


Include inserts Module as anonymous super class with instance methods and variables.
19 Aug, 2010, JohnnyStarr wrote in the 48th comment:
Votes: 0
Okie Dokie.

Edit: I see, you are not making Player have an initialize()

How would that workout when the idea is to implement multiple, sometimes many modules?
19 Aug, 2010, Tyche wrote in the 49th comment:
Votes: 0
JohnnyStarr said:
Okie Dokie.

Edit: I see, you are not making Player have an initialize()

If Player has an initialize, it need call super. It probably would or should in any case. If that's not satisfactory, you lazy initialize @inventory from instance methods in module Carries.

P.S. On e way is instead of using attr_accessor define lazy initialization in accessors. And it would seem to me you probably don't want a setter method. So…

module Carries
def inventory
@inventory||=Inventory.new("Blade of Gondor")
end
end
19 Aug, 2010, Runter wrote in the 50th comment:
Votes: 0
You may have to call super. Otherwise it may effectively override.
19 Aug, 2010, JohnnyStarr wrote in the 51st comment:
Votes: 0
module Boss
def initialize
puts "so boss!"
super
end
end

module Pal
def initialize
puts "whats up pal?"
super
end
end

class Friend; include Boss; include Pal; end

f = Friend.new

#=> whats up pal?
#=> so boss!


ME LIKES :biggrin:
19 Aug, 2010, Runter wrote in the 52nd comment:
Votes: 0
When there are many modules defining the same methods super must be called down the chain if you don't want overriding.

Because there I'd no multiple inheritance mix in are not equal. Lifo.
19 Aug, 2010, Runter wrote in the 53rd comment:
Votes: 0
module M
attr :is_fine
end

That's in response to where it can be used in a module.

And I brought it up because you were using the costly class eval to redefine it every time an obj was instanced.
21 Aug, 2010, JohnnyStarr wrote in the 54th comment:
Votes: 0
You are correct on that one :biggrin:
I got a bit ahead of myself by calling class_eval didn't I? Well, thanks to this discussion I know quite a bit more about modules.
So thanks guys.

BTW, I came up with my own "import" method which doesn't really care where a file is stored, just that it exists somewhere in the
project. During initial boot, this will "require" all ruby files in all source folders, and those will call "import" for dependencies. This is
really handy because you could end up changing your entire folder hierarchy later and it wouldn't matter at all.

# this resides in the run script polaris.rb

$imports = {}

def import(*files)
for f in files
if $imports[f]
require($imports[f])
else
raise "Import Error: #{f}.rb does not exist."
end
end
end

rb = File.join("**", "*.rb")
files = Dir.glob(rb)

files.each {|f| $imports[File.basename(f, ".rb").to_sym] = f}

$imports.each do |k,v|
next if k == :polaris
require(v)
puts "loaded #{k} -> #{v}"
end

# Example OUTPUT
#loaded character -> lib/core/base/character.rb
#loaded obtains -> lib/core/base/modules/obtains.rb

# in mobile.rb

import :character, :obtains

class Mobile < Character
include Obtains
end
40.0/54