YAML-JSON 変換するコマンドを Ruby で実装するメモです。
YAML to JSON 変換
はりきって作ろうと思ったのですが、以下の実装で十分でした。
#!/usr/bin/env ruby
require 'yaml'
require 'json'
puts JSON.pretty_generate YAML.load ARGF.read
# vi:set ts=2 sw=2 et:
これだけで済むんですね。ググっても該当コマンドが無いわけです。
JSON to YAML 変換
一応、こっちも掲載。
#!/usr/bin/env ruby
require 'yaml'
require 'json'
puts YAML.dump JSON.load ARGF.read
# vi:set ts=2 sw=2 et:
#付記
上のスクリプトは Ruby 2.1.5 で確認しています。
入力ファイルが日本語の場合、Ruby のバージョンにより、以下のような対処が必要かも知れません。(が、確認してません)
Ruby 1.9.x の場合は、先頭行、または shebang の次の行にマジックコメントを付ける。
@otn さんからご指摘いただきました。(コメント欄を参照ください)
マジックコメントは IO のエンコーディングと関係ありません。
Ruby 1.8.x 以前の場合は、$KCODE を設定する。
$KCODE = 'UTF-8' if RUBY_VERSION < '1.9'
もう少しましな版
(※ 2014.12.20 追記)
一つのスクリプトにまとめました。以下のモードを持ちます。
- YAML -> JSON 変換モード .......... YAML を入力、JSON を出力
- YAML -> JSON 変換モード (非pp) ... YAML を入力、JSON(非整形)を出力
- JSON -> YAML 変換モード .......... JSON を入力、YAML を出力
- 無変換モード ..................... 入出力を変換しない
変換モードのデフォルトは、ファイル名で決まります。
- yj.* の場合、デフォルトは YAML -> JSON 変換モード
- jy.* の場合、デフォルトは JSON -> YAML 変換モード
- 上記以外、デフォルトは 無変換モード
私は、パスの通ったディレクトリにシンボリックリンクを張って使っています。
$ cd ~/bin/ # 私の環境ではここにパスが通っています
$ ls yb.rb
yb.rb
$ chmod +x yj.rb
$ ln -s yj.rb yj # 「yj」という名前のコマンドとして使う
$ ln -s yj.rb jy # 「jy」という名前のコマンドとして使う
変換モードのデフォルトに関わらず、オプションでモードを指定できます。
- --yj ...... YAML -> JSON 変換モード
- --yJ ....... YAML -> JSON 変換モード (非pp)
- --jy ....... JSON -> YAML 変換モード
- -n ......... 無変換モード
cat コマンドと同じく、標準入力または引数で指定したファイルの内容を、上記の変換モードで変換して標準出力に出力します。
入力ファイルは複数指定できます。それぞれのファイル単位で変換をします。ただし、出力が混ざってしまうので、複数ファイルの指定は実用的ではありません。
'open-uri' ライブラリの仕様に従い、ファイル名として URI が指定された場合は、HTTP GET します。
下は、指定の URI にある JSONファイルを YAML に変換して標準出力に表示する例です。
$ ruby yj.rb --jy http://localhost/some.json
スクリプトは以下です。
#!/usr/bin/env ruby
require 'open-uri'
require 'optparse'
require 'yaml'
require 'json'
fi = fo = -> s { s }
yj_mode = -> { fi = YAML.method:load ; fo = JSON.method:pretty_generate }
yJ_mode = -> { fi = YAML.method:load ; fo = JSON.method:generate }
jy_mode = -> { fi = JSON.method:load ; fo = YAML.method:dump }
case File.basename $0, '.*'
when 'yj' ; yj_mode.()
when 'jy' ; jy_mode.()
end
OptionParser.new.instance_eval do
on('--yj', 'YAML -> JSON モード ') { yj_mode.() }
on('--yJ', 'YAML -> JSON モード (非pp)') { yJ_mode.() }
on('--jy', 'JSON -> YAML モード ') { jy_mode.() }
on('-n' , '無変換 モード ') { fi = fo = -> s { s } }
parse!
end
fp = -> s { print fo.(fi.(s)) }
if ARGV.empty?
fp.($<.read)
else
ARGV.each {|fname| open(fname) {|f| fp.(f.read) }}
end