自作Gemに設定コマンドを導入する

# はじめに
　rubyのgemはthorを利用することで簡単にコマンドを作成することができる.  コマンドをつける目的としては, なんらかの操作（APIを叩く，ファイル生成など）を自動化するというものが多いだろう.
　そういった操作には, しばしば入力が必要となるが, 毎回同じ入力をするのは非常にめんどくさい.
　そこで, 入力する情報や設定を保存し, それを利用する方法について書く.  具体的には, configコマンドを作成し, 設定を保存するとともに, 他のコマンドからその情報を利用してみる.

 最終的にできあがるものは, 以下のようなものである.

```sh
$ bundle exec mygem config
Input your name: User name # User nameを入力
Update Your name to [User name].

$ bundle exec mygem hello 
Hello!, User name # 保存したデータを利用する
```

# 準備: gemの作成とhelloコマンドの作成

## gemの準備
まずは、bundlerを利用してgemを作成する。

```sh
$ bundle gem mygem
$ cd mygem
```

mygem.gemspecのTODOとなっているところを編集する。また、thorをインクルードしておく。

```rb:./mygem.gemspec
  .
  .
  spec.summary       = %q{mygem}
  spec.description   = %q{mygem}
  spec.homepage      = "#githubのレポジトリなど"
  .
  .
  # thorを依存gemに追加
  spec.add_dependency "thor"
end
```

## helloコマンドの作成
thorについて詳しくない方のために,
本題に入る前にHello!と出力するだけのhelloコマンドを作ってみる.
以下のようにファイルを準備する.

```./lib/mygem/command/hello.rb
require 'mygem'
require 'mygem/command'

module Mygem
  class Command < Thor
    desc 'hello', 'say Hello!'
    def hello
      puts "Hello!"
    end
  end
end

```

```./lib/mygem/command.rb
require 'mygem'
require 'thor'
require 'mygem/command/hello'

module Mygem
  class Command < Thor
  end
end

```

```./lib/mygem.rb
require "mygem/version"
require "mygem/command"

module Mygem
end

```

gemの実行ファイルを作成する.

```rb:./mygem/exe/mygem
require 'mygem'
Mygem::Command.start
```

ビルド＆インストール＆実行する.

```sh
$ git add -A .
$ git commit -m 'init'
$ rake build
$ rake install
$ bundle install
$ bundle exec myconfig
Commands:
  mygem hello           # Say Hello!
  mygem help [COMMAND]  # Describe available commands or one specific command
$ bundle exec mygem hello
Hello!
```

これでmygemにhelloコマンドが追加された.

# 本題: configコマンドの作成と実行
　今回は,データの保存先をホームディレクトリ直下の, gem名の隠しディレクトリ以下とする.
つまり, ~/.mygem/settings.yml である.
## ヘルパーメソッドの作成
　さて, configコマンドを作成するに当たり, やりたいことは以下の3つである.

- コンフィグを設定する
- コンフィグを保存する
- コンフィグを取得する

　settings.ymlに対して上の３つを行うヘルパーメソッドを以下のように作成する.

```./lib/mygem/helper/config_helper.rb
require 'fileutils'
require 'yaml'
require 'psych'

module Mygem
  # Configuration defaults
  @config = {
      name: 'default'
  }
  @valid_config_keys = @config.keys

  # Configure through hash
  def self.configure(opts = {})
    self.config
    opts.each do |k, v|
      @config[k.to_sym] = v if @valid_config_keys.include? k.to_sym
    end
    self.save_config
  end

  def self.get_config_path
    config_path = Dir.home + '/.mygem'
    if Dir.exists?(config_path)
      # use user settings
      config_path
    else
      raise "Can't find config directory. please init by command: 'mygem config'.'"
    end
  end

  # configをyamlから@cofigに取得
  def self.config
    yml_path = get_config_path + '/settings.yml'
    yml_file = YAML.load_file(yml_path)
    if yml_file
      @config = yml_file
    else
      File.open(yml_path, 'w') { |f| YAML.dump(@config, f) }
    end
  end

  # 現在の@configをyamlに保存
  def self.save_config
    yml_path = get_config_path + '/settings.yml'
    if File.exists?(yml_path)
      File.open(yml_path, 'w') { |f| YAML.dump(@config, f) }
    else
      raise "Can't find #{yml_path}. please set configure."
    end
  end
end

```

```./lib/mygem.rb
require 'fileutils'
require 'yaml'
require 'psych'
require "mygem/version"
require "mygem/command"
require 'mygem/helper/config_helper' # 追加

module Mygem
end
```

config_helperでは, Mygem.configure(name: 'name')とした後で, save_configで現在のconfigをyamlに保存する.
そして, データが保存してあれば Myconfig.config[:name] でデータが取り出せるようになる.

## configコマンドの作成
　configの設定, 保存, 参照ができるようになったので, いよいよconfigコマンドを作成する.
　configコマンドでやることは, 以下の３つである.

- 初回起動時に設定ファイルを作成
- 入力を受け付ける
- 入力を設定として保存する

　これを以下のように実装する.

``` ./mygem/lib/mygem/command/config.rb
require 'mygem'
require 'mygem/command'

module Mygem
  class Command < Thor
    desc 'config', 'change settings'
    def config
      # 初回起動時に設定ファイルを作成
      config_path = Dir.home + '/.mygem'
      if Dir.exists?(config_path)
        puts "Your current name is [#{Mygem.config[:name]}]."
      else
        Dir.mkdir(config_path)
        yml_path = Mygem.get_config_path + '/settings.yml '
        File.open(yml_path, 'w').close
      end

      # 入力を受け付ける
      print 'Input your name: '
      loop do
        s = $stdin.gets.chomp!
        if s.size != 0
          # 設定を更新
          Mygem.configure(name: s)
          break
        else
          puts 'Invalid Name. please try again:'
        end
      end
      puts "Update Your name to [#{Mygem.config[:name]}]."
    end
  end
end


```

``` ./lib/myconfig/command.rb
require 'myconfig'
require 'thor'
require 'myconfig/command/hello'
require 'myconfig/command/config' # 追加

module Myconfig
  class Command < Thor
  end
end

```

## 設定を利用する
　これで自由にnameを設定できるようになったので, 最後にhelloを更新して設定を利用するようにする.

``` ./mygem/lib/mygem/command/hello.rb
require 'mygem'
require 'mygem/command'

module Mygem
  class Command < Thor
    desc 'hello', 'call your name and say Hello!'
    def hello
      puts "Hello, #{Mygem.config[:name]}!"
    end
  end
end

```

以上で完成したので, ビルド&インストールして使ってみる.

```sh
$ rake build; rake install
$ bundle install
$ bundle exec mygem
Commands:
  mygem config          # Change settings
  mygem hello           # Call your name and say Hello!
  mygem help [COMMAND]  # Describe available commands or one specific command
$ bundle exec mygem hello
# 設定をしていないのでエラーが表示される
$ bundle exec mygem config                                                                                                                             
Input your name: Myname
Update Your name to [Myname].
$ bundle exec mygem hello
Hello!, Myname
$ bundle exec mygem config
Your current name is [Myname].  # 現在の設定が表示される
Input your name: New Name
Update Your name to [New Name]. # 設定を更新
$ bundle exec mygem hello
Hello!, New Name                # 新しい名前が表示される
```

保存されているファイルを見てみると, 以下のように保存されている.

```yaml:~/.myconfig/settings.yml
---
:name: New Name
```

おわり

# 参考
今回作成したgem
https://github.com/keigo-brook/gem_myconfig

http://qiita.com/kasaharu/items/c84d393cf7fa13cc4b3d

http://stackoverflow.com/questions/6233124/where-to-place-access-config-file-in-gem