Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hash as source #10

Open
sheldonh opened this issue Oct 1, 2015 · 3 comments
Open

Hash as source #10

sheldonh opened this issue Oct 1, 2015 · 3 comments

Comments

@sheldonh
Copy link

sheldonh commented Oct 1, 2015

I can't figure out how to use a Hash as source. I try this:

require 'settingslogic'

class MySettings < Settingslogic
  source("name" => "Sheldon")
end

puts MySettings.name

And I get this:

/home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:172:in `class_eval': (eval):3: syntax error, unexpected tIDENTIFIER, expecting ')' (SyntaxError)
...issing setting 'name' in {"name"=>"Sheldon"}") unless has_ke...
...                               ^
(eval):3: syntax error, unexpected tCONSTANT, expecting keyword_end
...ing 'name' in {"name"=>"Sheldon"}") unless has_key? 'name'
...                               ^
(eval):3: syntax error, unexpected ')', expecting keyword_end
...'name' in {"name"=>"Sheldon"}") unless has_key? 'name'
...                               ^
(eval):6: syntax error, unexpected tIDENTIFIER, expecting ')'
...alue, "'name' section in {"name"=>"Sheldon"}")
...                               ^
(eval):6: syntax error, unexpected tCONSTANT, expecting keyword_end
...e' section in {"name"=>"Sheldon"}")
...                               ^
(eval):6: syntax error, unexpected ')', expecting keyword_end
    from /home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:172:in `create_accessor_for'
    from /home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:148:in `block in create_accessors!'
    from /home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:147:in `each'
    from /home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:147:in `create_accessors!'
    from /home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:113:in `initialize'
    from /home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:60:in `new'
    from /home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:60:in `instance'
    from /home/sheldonh/.gem/ruby/2.2.3/gems/settingslogic-2.0.9/lib/settingslogic.rb:11:in `name'
    from setwhat.rb:7:in `<main>'

Does that code still work?

@sheldonh
Copy link
Author

sheldonh commented Oct 1, 2015

I see there aren't any tests that cover this use case, which seems to have been broken for a while. The problem is that source is used unconditionally as the section when the section is not explicitly provided.

That doesn't suit the "Hash as source" use case, because the source() method doesn't allow the caller to provide a section name to pass through to initialize().

We could either use "Hash" as the section name when hash_or_file is a Hash, or we could extend the source() method to take an optional section name. That'll get a bit messy.

Thoughts?

@deemytch
Copy link

Trying to load hash with the same success as @sheldonh

class AppConfig < Settingslogic
    [...]
    def self.load_from_redis
        r = Redis.new url: ENV['REDIS-URL']
        cfg = JSON.parse r.get("cfg.#{ Rails.env }")
        r.quit
        return cfg
    end
    source( self.load_from_redis )
end

SyntaxError: (eval):3: syntax error, unexpected tIDENTIFIER, expecting ')'
...etting 'redis_db' in {"redis_db"=>{"auth"=>2, "sidekiq"=>3, ...

etc

@josvazg
Copy link

josvazg commented Nov 27, 2019

I run into this, I used this to make it work:

  class SomeConfig < Settingslogic
    source(**some_hash)

    # This is overridden from the original code because for the "hash as input"
    # code path keys enforced to be symbols by the constructor args, but then the
    # eval code in #create_accessor_for is setup to search for strings
    # I guess the usual "config file" code path works fine because the keys
    # are strings there, but the hash is generated inside the constructor
    def replace(hash)
      hash.keys.each do |key|
        next unless key.is_a? Symbol

        hash[key.to_s] = hash[key]
      end
      super
    end

    class << self
      private

      def instance
        return @instance if @instance

        # This constructor call is changed from the original code because
        # passing a "hash as input" with section nil will break the eval code
        # in #create_accessor_for when displaying the section
        @instance = new(@source, 'hash')
        create_accessors!
        @instance
      end
    end
  end

So basically I found 2 issues to be able to use the config from a hash source:

  1. I had to override the class instance method to ensure the section argument was passed in and was not nil, which will break the #create_accessor_for eval code.
  2. I also had to override #replace to make sure the hash to be replaced could find the values also from string keys. That after the constructor of the instance forced them to be symbols passed in.

But yes not sure what is the best fix for the upstream class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants