LoginSignup
3
0

More than 3 years have passed since last update.

Ruby Gem Code Reading settingslogic 編その1

Posted at

背景

この記事を読んで、コードリーディングしながらRubyの知識深めようと思ったため
https://blog.freedom-man.com/try-rubygem-codereading

対象

settinglogic

コードを読む準備をする

対象のgem をインストールする

$ bundle init

さっそく最初からつまずく..

$ gem install settingslogic
ERROR:  Loading command: install (LoadError)
    dlopen(/Users/XXXX/.rbenv/versions/2.4.2/lib/ruby/2.4.0/x86_64-darwin16/openssl.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib
  Referenced from: /Users/XXXX/.rbenv/versions/2.4.2/lib/ruby/2.4.0/x86_64-darwin16/openssl.bundle
  Reason: image not found - /Users/XXXX/.rbenv/versions/2.4.2/lib/ruby/2.4.0/x86_64-darwin16/openssl.bundle
ERROR:  While executing gem ... (NoMethodError)
    undefined method `invoke_with_build_args' for nil:NilClass

opensslのリンクがおかしくなっているのが原因らしく、こちらの記事を参考に修正
https://qiita.com/Capotasto/items/16be7620c4eed42efccb
https://qiita.com/YoshiyukiKato/items/e4f67c588d2943c1253d

$ brew uninstall --force --ignore-dependencies openssl
$ brew install openssl
$ brew link openssl 
$ rbenv uninstall 2.4.2
$ rbenv install 2.4.2

これで行けた。

$ echo 'source "https://rubygems.org"' >> ./Gemfile
$ echo 'gem "settingslogic"' >> ./Gemfile
$ echo 'gem "pry"' >> ./Gemfile
$ bundle config set --local path 'vendor/bundle'
$ bundle install

対象のファイルを確認

fileは1ファイルだけ
settingslogic.rb

コードの中身をざっと見てみる

class Settingslogic < Hash

Hashクラスを継承しているらしい

keyとvalueをかんたんに突っ込みやすくしてるのかな?

    def [](key)
      instance.fetch(key.to_s, nil)
    end

    def []=(key, val)
      # Setting[:key][:key2] = 'value' for dynamic settings
      val = new(val, source) if val.is_a? Hash
      instance.store(key.to_s, val)
      instance.create_accessor_for(key, val)
    end

この辺はHashクラスのオーバーライドっぽい

new(val, source)

newってこんな書き方できるんだ。ここではクラス内のinitializeが呼ばれ(初期化),指定されたkeyで現状のインスタンスに追加されていますね。

というか演算子の挙動をメソッドとしてオーバーライドできるんですね。

  def initialize(hash_or_file = self.class.source, section = nil)
    #puts "new! #{hash_or_file}"
    case hash_or_file
    when nil
      raise Errno::ENOENT, "No file specified as Settingslogic source"
    when Hash
      self.replace hash_or_file
    else
      file_contents = open(hash_or_file).read
      hash = file_contents.empty? ? {} : YAML.load(ERB.new(file_contents).result).to_hash
      if self.class.namespace
        hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}")
      end
      self.replace hash
    end
    @section = section || self.class.source  # so end of error says "in application.yml"
    create_accessors!
  end

ここでyamlを読み込むみたい。この中の

 if self.class.namespace
        hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}")
 end

ここは指定したnamespaceのデータだけhashとして使うってことかな

使ってみる

settings.yaml
defaults: &defaults
  cool:
    saweet: nested settings
  neat_setting: 24
  awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>

development:
  <<: *defaults
  neat_setting: 800

test:
  <<: *defaults

production:
  <<: *defaults
setting.rb
require 'settingslogic'

class Settings < Settingslogic
  source File.expand_path("../settings.yml", __FILE__)
  namespace ENV['ENV']
end
sample.rb
require File.expand_path("../settings.rb", __FILE__)

puts Settings.neat_setting
puts Settings.awesome_setting
puts Settings.cool.saweet

\w $ ENV=production ruby sample.rb 
24
Did you know 5 + 5 = 10?
nested settings

ひとまずざっくりは追いかけられた。
railsに入れてから試すのもいいが、ラクしたかったのでちょくで出力した。

公式見るとdynamic bindingなどがあるのだが、
直で実行するとエラーになってしまう。。

次はRailsに入れつつもう少しコード追いかけよう。

200行もないので割ととっつきやすい。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0