Hi! I'm quite new to Ruby, and am quite confused about instance names. I am in the middle of writing an app that has a good number of configuration files, and I'd like to write: basic_config = MySettings.new # Picks up & processes basic_config.yml adv_config = MySettings.new # Picks up & processes adv_config.yml I'm using SettingsLogic to the hard work, so MySettings looks a bit like this: class MySettings < SettingsLogic source instance.name # For example # Do some other stuff end I tried my_class.name; that returns a "Method not defined" error" (I'm using 1.9.3p194) What I'd really like to avoid is: basic_config = MySettings.new(basic_config). As far as I can tell, what I want to do isn't possible. I did ask on StackOverflow and Boris was a great help, but his code requires a :name => some_name flag. So I figured I'd ask here and see if anyone can help me! Can I do what I want to do? Thanks in advance! Carolyn
on 2012-11-11 05:21
on 2012-11-11 10:25
Am 11.11.2012 05:21, schrieb Carolyn Grant: > > > basic_config = MySettings.new(basic_config). > > As far as I can tell, what I want to do isn't possible. I did ask on > StackOverflow and Boris was a great help, but his code requires a :name > => some_name flag. So I figured I'd ask here and see if anyone can help > me! Can I do what I want to do? This could not work for several reasons: - the object is created first, before it can be assigned to a variable - a single object could be referenced by several variables - and of course: you can create and use objects without ever assigning them to a variable: `puts Time.new' What's wrong with config = MySettings.new('basic_config') [or config = MySettings.new('basic_config.yml') ] where the initialize method accepts a file name?
on 2012-11-11 10:31
Carolyn Grant wrote in post #1083906: > basic_config = MySettings.new # Picks up & processes basic_config.yml > adv_config = MySettings.new # Picks up & processes adv_config.yml In general it doesn't make any sense for an object to know its "name", because an object may have zero or many names at any time. You can assign the object reference to local variables, to global variables, to instance variables of other objects, to constants, as elements of an Array or Hash, etc. In the above code, the object created by MySettings.new has no name at the time it is created. Only after the #new function has returned the object reference, it is assigned to the local variable. So for the code you are writing above, I would strongly advise passing the filename (or filename stem) as an argument: basic_config = MySettings.new("basic_config.yaml") adv_config = MySettings.new("adv_config.yaml") Of course, as with many things in Ruby, there is an exception. The exception is to do with class objects; that is, objects of class Class. Normally classes are held in constants, and the first time a class is assigned to a constant, it learns its name, and the name becomes an attribute of the class itself. A class definition like "class Foo" both creates the class and assigns it to a constant, but you can see the behaviour if you first create an anonymous class, and then later assign it to a constant. >> foo = Class.new => #<Class:0x106c91650> >> my_instance = foo.new => #<#<Class:0x106c91650>:0x106c8e6f8> >> Bar = foo => Bar >> foo => Bar >> my_instance => #<Bar:0x106c8e6f8> >> Baz = foo => Bar >> foo => Bar >> my_instance => #<Bar:0x106c8e6f8> > I tried my_class.name; that returns a "Method not defined" error" (I'm > using 1.9.3p194) You'll have to show the code. I use ruby 1.8, but it works fine for me. Notice that "name" is a method of the class, not the instance, and is only for Class objects because of the special-case behaviour described above. >> foo.name => "Bar" >> my_instance.class.name => "Bar" >> my_instance.name NoMethodError: undefined method `name' for #<Bar:0x106c8e6f8> from (irb):11 > What I'd really like to avoid is: > > basic_config = MySettings.new(basic_config). Why? It seems you want to create "magic" which will be very difficult for another programmer to follow. When you create an object, you should pass all the data which will be used to create state in that object, and you should allow the caller to decide what to do with the returned object. The closest I could recommend is if you have a single config object which holds all the sub-configs e.g. a hash. Then a single method argument can say which file to load *and* which hash member to put it in. For example: require 'yaml' class Configs def initialize @configs = {} end def load(stem) @configs[stem] = File.open("#{stem}.yaml") do |f| YAML.load(f) end end def [](stem) @configs[stem] end end config = Configs.new config.load "basic_config" config.load "adv_config" puts config["basic_config"].inspect Of course, if you want the config to be globally accessible throughout your application, then you can assign it to a constant instead of a local variable. Config = Configs.new Config.load "basic_config" Config.load "adv_config" puts Config["basic_config"].inspect Or you could use a global variable, but a constant is generally preferred. Constants can be put into namespaces, e.g. MyApp::Config, to avoid clashes with other uses of Config.
on 2012-11-11 10:34
Am 11.11.2012 10:24, schrieb sto.mar@web.de: > Am 11.11.2012 05:21, schrieb Carolyn Grant: >> Hi! I'm quite new to Ruby, and am quite confused about instance names. >> basic_config = MySettings.new # Picks up & processes basic_config.yml >> adv_config = MySettings.new # Picks up & processes adv_config.yml > config = MySettings.new('basic_config') If you have lots of config objects you then could also use an array or a hash that contains all of them: config[:basic] = MySettings.new('basic_config') config[:adv] = MySettings.new('adv_config')
on 2012-11-11 14:16
Brian Candler wrote in post #1083926: > >> What I'd really like to avoid is: >> >> basic_config = MySettings.new(basic_config). > > Why? It seems you want to create "magic" which will be very difficult > for another programmer to follow. When you create an object, you should > pass all the data which will be used to create state in that object, and > you should allow the caller to decide what to do with the returned > object. It just looked cleaner to me! Passing in the same name as the instance just seemed like another opportunity for a typo, and it just looked redundant. (The Readme would show the correct usage.) > I tried my_class.name; that returns a "Method not defined" error" (I'm > using 1.9.3p194) > You'll have to show the code. I use ruby 1.8, but it works fine for me. > Notice that "name" is a method of the class, not the instance, and is > only for Class objects because of the special-case behaviour described > above. Thanks for the clarification - I was trying to make it do what it can't! > > Of course, if you want the config to be globally accessible throughout > your application, then you can assign it to a constant instead of a > local variable. > > Config = Configs.new > Config.load "basic_config" > Config.load "adv_config" > puts Config["basic_config"].inspect > > Or you could use a global variable, but a constant is generally > preferred. Constants can be put into namespaces, e.g. MyApp::Config, to > avoid clashes with other uses of Config. I'm very leery of global constants, and I'm really nervous (literally!) about global environment variables. My ultimate goal was to provide a sophisticated [sic...] ValueObject that didn't need to be told what file to parse to get its values. I was hoping to release it as a gem, but all things considered - it certainly looks like it's either in Ruby, or vaguely possible but really difficult and not worth the effort. It was for a configuration system for a Sinatra app I'm in the middle of writing; I really don't like huge, global, configuration arrays (ala Rails), so I looked for an alternative. SettingsLogic got me most of the way there, but the need to specify the file, when its name was the instance name, just looked "messy". Oh well, thanks! I've decided that I need to rethink the problem.
on 2012-11-11 14:18
unknown wrote in post #1083928: > Am 11.11.2012 10:24, schrieb sto.mar@web.de: >> Am 11.11.2012 05:21, schrieb Carolyn Grant: >>> Hi! I'm quite new to Ruby, and am quite confused about instance names. > >>> basic_config = MySettings.new # Picks up & processes basic_config.yml >>> adv_config = MySettings.new # Picks up & processes adv_config.yml > >> config = MySettings.new('basic_config') > > If you have lots of config objects you then could also use an array > or a hash that contains all of them: > > config[:basic] = MySettings.new('basic_config') > config[:adv] = MySettings.new('adv_config') I started with that, and wondered if there was a "better way". :-) There doesn't seem to be, so I'm rethinking the problem and coming up with a different solution. (I have no idea what that might be, at the moment... Probably the duplicate-looking syntax I was trying to get away from.) Thanks!
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.