Skip to content

Instantly share code, notes, and snippets.

@Shinya131
Last active August 29, 2015 14:05
Show Gist options
  • Save Shinya131/ed125d3212d8db3c8c7f to your computer and use it in GitHub Desktop.
Save Shinya131/ed125d3212d8db3c8c7f to your computer and use it in GitHub Desktop.
railsのseed ファイルの中から指定したidのrecordに相当する部分のみを取り出します
# == seed picker ==
# railsのseed ファイルの中から指定したidのrecordに相当する部分のみを取り出します
#
# TODO: 指定したidが見つからない場合にエラーになるようにする
#
# #例
# <data source>
# /Users/nagai_shinya/my_rails_app/db/seeds/products.yml
#
# ````
# data1:
# id: 1
# name: "shampoo"
# data2:
# id: 2
# name: "rinse"
# data3:
# id: 3
# name: "sponge"
# data4:
# id: 4
# name: "aaaaa"
# ````
#
# <command>
# $ ruby seed_picker.rb /Users/nagai_shinya/my_rails_app/db/seeds/products.yml 2,3
#
# <result>
# ````
# data2:
# id: 2
# name: "rinse"
# data3:
# id: 3
# name: "sponge"
# ````
require 'yaml'
require 'pry'
# seedファイルをラップするclass
# - #recordsでrecordごとに分割されたseedをStringのArrayとして取り出せる
#
# #例
# <data source>
# |data1:
# | id: 1
# | name: 'doc'
# |data2:
# | id: 2
# | name: 'cat'
#
# <return of #records>
# [
# "data1: \n id:1\n name: 'doc'\n",
# "data2: \n id:2\n name: 'cat'\n"
# ]
#
# #背景
# 通常このような操作を行う場合は、
# 一度`YAML.load(seed)`してhashにした後、処理を行いその後、YAML.dump()すれば良い。
# しかし、YAML.dump(YAML.load(seed))すると元の文字列と差分が出てしまう。
#
# そのためにseedを文字列として扱いないながら、
# seedをrecordごとに取り出す操作が出来るようにしたのがこのclass.
#
class Seed
attr_reader :seed, :records
def initialize(seed)
@seed = seed
end
# seedをrecordごとに分けて返す
def records
if @records.nil?
setup_records
end
@records
end
private
# seedをrecordごとに分割して`@records`にストアする。
# seedが空になるまで先頭のrecordを繰り返し取り出している。
def setup_records
@records = []
seed = @seed.dup
loop do
if seed.empty?
break
end
@records << fetch_first_record!(seed)
end
end
# seedから先頭のrecoedを取り出す。
# このメソッドは引数にたいして破壊的操作を行う。
#
# 正規表現でrecoedとrecordの境目を探す。
# 見つかれば: (文字列先頭..record境目) の部分文字列を返す
# 見つからなければ: (文字列先頭..文字列末尾) の部分文字列を返す
def fetch_first_record!(seed)
record_boader = seed.index(record_boader_regexp)
if record_boader.nil?
return seed.slice!(0..-1)
end
seed.slice!(0..record_boader)
end
# recordとrecordの境目にマッチする正規表現。
# 改行の後にspace以外の文字列が来ている部分を境目とする。
#
# ex: 以下のseedなら` name: "doc"`の行末がマッチする。
# ````
# data1:
# id: 1
# name: "doc"
# data2:
# id: 2
# name: "cat"
# ````
#
# FIXME: tabインデントに対応
def record_boader_regexp
/\n[^ ]/
end
end
# seedファイルを1record分だけ切り取った文字列をラップするclass
# - #[key] でkeyに対応する値を取り出せる
# - #seed で文字列としてseedを取り出せる
#
# 以下の両方の要件を満たすために作った。
# 1. YAML.dump(YAML.load(seed))すると元の文字列と差が出てしまうので、
# seedをhashに変換して扱いたくない(文字列として扱いたい)
#
# 2. しかし、keyを使ってvalueにもアクセスしたい(Hashとして扱いたい)
#
# YAML文字列をラップして、それらの機能を提供しているのがこのclass.
#
class SeedForOneRecord
# seedデータを文字列として取得する。
# 常に、initializeの引数と同じ文字列がかえってくる
attr_reader :seed
def initialize(seed_for_one_record)
@seed = seed_for_one_record
end
# 指定したkeyに対応する値を取得する
#
# ex:
# <data source>
# ````
# data1:
# id: 1
# name: "doc"
# ````
# <haw to use>
# seed_for_one_record["id"] #=> 1
# seed_for_one_record["name"] #=> "doc"
def [](key)
content[key]
end
private
# seedのデータをhashとして取得する。
# メモ化あり。
#
# #ex
# <data source>
# ````
# data1:
# id: 1
# name: "doc"
# ````
#
# <return>
# {"data1" => {"id" => 1, "name" => "doc" }}
#
def exchange_to_hash
@seed_data_by_hash ||= YAML.load(@seed)
end
# hash化したseedからデータ部分を取り出す。
#
# ex:
# <data source>
# {"data1" => {"id" => 1, "name" => "doc" }}
#
# <return>
# {"id" => 1, "name" => "doc" }
#
def content
unless exchange_to_hash.size == 1
raise
end
content = exchange_to_hash.values.first
end
end
#FIXME: ちょうてきとう
seed_file_path = ARGV.shift
ids = ARGV.shift.split(',').map(&:to_i)
seed = Seed.new(File.read(seed_file_path))
target_records =
seed.records.map.select do |seed_for_1record|
record = SeedForOneRecord.new(seed_for_1record)
ids.include? record["id"]
end
puts target_records
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment