Last active
August 29, 2015 14:05
-
-
Save Shinya131/ed125d3212d8db3c8c7f to your computer and use it in GitHub Desktop.
railsのseed ファイルの中から指定したidのrecordに相当する部分のみを取り出します
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == 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