Hatena::Grouprubyist

altrのruby日記

2008-06-13

はてなグループを使うときの最大の罠

デフォルトが「グループ公開」になっているのに気づかないことが多い。また忘れてました。

フィルタを連結するような感じの変換スクリプト (1)

複数のcsvファイルからなにやら取ってきて、変換したり書き出したりするものを作っています。

  • 列の名前と、デフォルト値・変換ルーチンをyamlで定義
  • 列の名前はフィルタをまたいで共通とする(並べ替えを名前で指定)
  • 変換ルーチンは、その都度yamlに書くかわりに、よく使うものをマクロとして呼び出せるようにしています。
  • RuledFieldsは、他のRuledFieldsオブジェクトからget_record(),parse()して自分の中に一行保持します。

書き出してみると自分でなにやってるか怪しいなぁ。

  • 置換ルールを読む
  • ファイルから読むか、他objから貰うかして1行取り出す
  • 置換ルールにしたがって置換
  • データを保持

というオブジェクトを並べて、途中に出力があったりする複雑なプロセスのコンバートをやらせようということです。

memo

  • とりあえずlambdaって書いてみたかっただけです。
  • テストしないと、最初何がしたかったのかわからなくなる。rubyでTDDってどうやるんだろう。いや他のもののやりかたもよく知りませんが…。
  • そもそも一行ずつ処理とかする意味がなくて、メモリに全部溜めるか中間ファイルを作るかしたほうがいいみたい。

code

#!ruby -KS

require 'yaml'
require 'csv'

# ================  definition
MACRO_TABLE = {
  :TO_I => lambda{|x| x.to_i} ,
  :TIMEONLY => lambda{|x| x.match(/\b(\d{1,2}:\d{1,2}):\d{1,2}$/).to_a[1]} ,
  }
# ================ classes
class RuledFields
  attr_accessor :names , :rules, :defaults
  def initialize
    @separator = /\t/
    @glue = ","
    @data = nil
    @data_by_name = {}
    
    @names = []
    @rules = {}
    @defaults = {}
    # names: field order [:id, :name, :category_id]
    # rules: convert map {:id=>lambda{|x| x.to_i},..}
    # defaults: defaultv {:id=>0, ...}
  end
  
  # fetch from object
  def fetch_from obj
    data_imported = obj.get_record
    @data_by_name = self.parse(data_imported)
  end
  
  # parsing according to rule
  def parse(data_hash)
    # order keys, convert values, insert default
    rethash = {}
    @names.each{|aname|
      value = data_hash[aname]
      if (value == nil && @defaults[aname]) then
        value = @defaults[aname]
      end
      if(@rules[aname] && value != nil) then
        value = @rules[aname].call(value)
      end
      rethash[aname] = value
    }
    return rethash
  end
  
  # set record aline
  def set_data(data)
    @data = data
    self.prepare_record
  end
  def prepare_record
    # re-map to names
    return unless @data
    @names.each_with_index{|name, idx|
      @data_by_name[name] = @data[idx]
    }
  end
  
  def load_rules (filename)
    # rf2.names = [:name, :id , :hoge]
    # rf2.defaults = {:hoge=>'0000'}
    # rf2.rules = {:name=>lambda{|x| x.upcase}}
    yaml_fi = open(filename)
    lines = yaml_fi.readlines.join('')
    obj = YAML::load(lines)
    yaml_fi.close
    
    obj['fields'].each{|fparam|
      @names << fparam['fieldname'].to_sym
      if fparam['default']
        @defaults[fparam['fieldname'].to_sym] = fparam['default']
      end
      if fparam['rule']
        @rules[fparam['fieldname'].to_sym] = eval(fparam['rule'])
      end
      if fparam['macro']
        @rules[fparam['fieldname'].to_sym] = MACRO_TABLE[fparam['macro'].to_sym]
      end
    }
  end
  
  def get_record
    @data_by_name
  end
  def get_record_by_name names
    # return fields by name
    @data_by_name[names]
  end
end

yamlはこんな感じで。

name: companies
file: companies_source.txt
encoding: utf8
fields: 
- fieldname: id
  default: 100
  macro: TO_I
- fieldname: company_id
  macro: TO_I
- fieldname: group_id
  macro: TO_I
- fieldname: open_time
  macro: TIMEONLY
#....

profile/usage

| 09:53

30代のおっさんです。未来がないなりに頑張ります。

  • 「知ったかぶりで手を動かして努力せず打ち筋が悪い」というのを直す。
  • とりあえずコードを貼る。それを日本語で説明する練習をする。
  • ITヒジカタ的な話でも書く(ここ重要)。知識の格差が生まれるとしたらそういう話を恥ずかしくて書かないせい。