2011-02-02

easy_fabricator とか作ってみた。

あるいは。

Ruby で動的に class を定義したかった。

twitter 上で何人かにそんなんできるよって言われたんだけど、どうにも伝わらなかった部分。

class を生成したいんじゃなくて、class 構文を使わずに class を定義したい。

なんでかというと

Fabricator は Model 相当の class の名前を Symbol で与えて使うから

ゴニョゴニョしてできたものはこれ。

#! /usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'optparse'
require 'singleton'
require 'rubygems' unless defined? ::Gem
require 'fabrication'
class EasyFabricator
class Configure
include Singleton
def initialize
@_fields = nil
@_fab = nil
end
def fields
if block_given?
@_fields = yield
else
@_fields
end
end
def fab( &block )
if block_given?
@_fab = block
else
@_fab.call if @_fab
end
end
end
def self.configure(&block)
block.call(Configure.instance)
end
def initialize
@num = 1
@format = 'csv'
@config = Configure.instance
end
attr_reader :config
def run
args.parse!( ARGV )
if ( file = ARGV.shift and File.exist?( file ) )
load file
Object.const_set( 'Model', Struct.new( *config.fields ) )
config.fab
send( "output_#{@format}" )
else
puts args
end
end
def output_csv
require 'fastercsv' if RUBY_VERSION < '1.9'
puts FasterCSV.generate { |csv|
csv << config.fields
}
puts FasterCSV.generate { |csv|
@num.times {
c = Fabricate.build( :model )
csv << config.fields.map { |field|
c[field]
}
}
}
end
def output_yaml
$KCODE = 'u' unless defined? ::Encoding
puts (1..@num).to_a.map { |id|
record = Fabricate.build( :model )
hash = {}
record.each_pair { |k, v|
hash[k.to_s] = v
}
to_yaml( id => hash ).sub( /--- \n/, '' )
}
end
def args
OptionParser.new { |opt|
opt.banner << " fabricator"
opt.on( '-n', '--num NUM ( default 1 )' ) { |num|
@num = num.to_i if num =~ /\A[0-9]+\z/
}
opt.on( '-y', '--output-yaml' ) {
@format = 'yaml'
prepare_yaml
}
opt.on( '-c', '--output-csv ( default )' ) {
@format = 'csv'
}
}
end
private
def prepare_yaml
begin
require 'ya2yaml'
rescue LoadError
require 'yaml'
end
class << self
if ( defined? Ya2YAML )
def to_yaml( obj )
obj.ya2yaml
end
else
def to_yaml( obj )
obj.to_yaml
end
end
end
end
end
if ( __FILE__ == $0 )
EasyFabricator.new.run
end

具体的に困ったこと、解決したことは何か

  • Object.const_set( NAME, classobj ) で好きなタイミングで class 定義できる
    • Klass = な書き方はメソッドの中では不可能
  • fabrication の DSL はちょっと注意が必要

例えば open や catch とかって attribute を用意してしまうと困る。

Fabricator( :model ) do
  open  { ... }
  catch { ... }
end

って書き方になるんだけど、これは通常のメソッド呼び出しになるので定義できない。

回避方法あるのかなぁ。あったら嬉しいんだけど。ダミーデータ用のツールのために元の名前に制限があったらちょっと本末転倒だよね。

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm