Rails生成器
前言
最初接触Rails时,就是被其强大的生成器所吸引的,少量的代码 + 几条命令,一个web程序就搭起来了。结果,工作中却很少使用,都是手工创建的,明明命令啊、自动化啊,什么的超棒了。
正文
Rails命令创建程序(rails new app
)时,使用了生成器。rails generate
列出项目中使用的所有生成器,其中部分列出如下:
Rails: assets controller generator helper `inherited_resources_controller` `integration_test` jbuilder mailer migration model observer `performance_test` resource `responders_controller` scaffold `scaffold_controller` `session_migration` task
ActiveRecord: `active_record:devise` `active_record:migration` `active_record:model` `active_record:observer` `active_record:session_migration`
Bootstrap: bootstrap:install bootstrap:layout bootstrap:partial bootstrap:themed
Devise: devise devise:install devise:views
Kaminari: kaminari:config kaminari:views
Mongoid: mongoid:config mongoid:devise
Rspec: rspec:feature rspec:install rspec:job
备注: 一些gem自生也会提供生成器,也就说生成器很常见。
Rails 3.0中,生成器使用Thor开发,命令行解析和文件处理的API。
生成器主要就是在Rails应用程序中lib/generators/目录下,创建类似xxx_generator.rb
这样的文件,然后,在其中写入如下的内容:
class InitGenerator < Rails::Generators::Base
def create_init_file
create_file "config/initializers/init.rb", "# Add initialization content here"
end
end
值得注意的是,生成器所继承的类,以及其使用的Thor方法 - create_file。 其实,生成器就是命令行程序。可以在调用生成器时,添加--help
查看说明。
可以使用生成器生成生成器: rails generate generator initializer
, 所谓的元编程。生成生成器的生成器继承类稍微不同
class Init1Generator < Rails::Generators::NamedBase # 生成生成器的生成器继承的类
source_root File.expand_path("../templates", __FILE__) # 模板文件存放的是生成器使用的模板
end
执行命令rails generate init
, Rails希望从如下的目录列表中找到init_generator.rb文件:
- rails/generators/initializer/
- generators/initializer/
- rails/generators/
- generators/
这些目录的前缀是$LOAD_PATH中的路径,例如lib目录。$LOAD_PATH可以在irb访问,本地的路径如下(RVM的加载路径好复杂):
["/home/xiajian/.rvm/rubies/ruby-1.9.3-p547/lib/ruby/site_ruby/1.9.1", "/home/xiajian/.rvm/rubies/ruby-1.9.3-p547/lib/ruby/site_ruby/1.9.1/x86_64-linux", "/home/xiajian/.rvm/rubies/ruby-1.9.3-p547/lib/ruby/site_ruby", "/home/xiajian/.rvm/rubies/ruby-1.9.3-p547/lib/ruby/vendor_ruby/1.9.1", "/home/xiajian/.rvm/rubies/ruby-1.9.3-p547/lib/ruby/vendor_ruby/1.9.1/x86_64-linux", "/home/xiajian/.rvm/rubies/ruby-1.9.3-p547/lib/ruby/vendor_ruby", "/home/xiajian/.rvm/rubies/ruby-1.9.3-p547/lib/ruby/1.9.1", "/home/xiajian/.rvm/rubies/ruby-1.9.3-p547/lib/ruby/1.9.1/x86_64-linux"]
定制工作流程
Rails自带的生成器允许在config/application.rb
中定制脚手架,默认值如下:
config.generators do |g|
g.orm :active_record
g.template_engine :erb
g.test_framework :test_unit, fixture: true
end
脚手架生成器只是调用其他生成器(erb,test_unit,help等)完成操作,定制工作流程,禁止生成样式表、JavaScript和测试固件:
config.generators do |g|
g.orm :active_record
g.template_engine :erb
g.test_framework :test_unit, fixture: false
g.stylesheets false
g.javascripts false
end
生成生成器的命令: rails generate generator rails/my_helper
,其生成器的代码片段:
# lib/generators/rails/my_helper/my_helper_generator.rb
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
def create_helper_file
create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
module #{class_name}Helper
attr_reader :#{plural_name}, :#{plural_name.singularize}
end
FILE
end
hook_for :test_framework, as: :helper # 添加辅助方法测试类的框架。
end
备注: HERE文档的作用,可以用作生成代码的字符串模板。
类似如下的代码称为程序模板:
# template.rb,使用: rails new thud -m template.rb
gem "rspec-rails", group: "test"
gem "cucumber-rails", group: "test"
if yes?("Would you like to install Devise?")
gem "devise"
generate "devise:install"
model_name = ask("What would you like the user model to be called? [user]")
model_name = "user" if model_name.blank?
generate "devise", model_name
end
thor中大量可在生成器和模板中使用的方法:
Gemfile相关:
- gem 选项有 :group, :version, :git, :branch
- gem_group 多个gem包一个分组
- add_source 代码库的源
其他诸多方法: inject_into_file
, gsub_file
, application(配置application.rb), git, vendor, lib, rakefile, initializer(在程序config/initializers中新建初始化脚本), generate(运行生成器), rake(运行rake任务), capify!(生成Capistrano配置), route(向路由添加内容), readme
傲娇的使用Disqus