创建你自己的Generator

今天写了个简单的generator,发现比想像的要简单许多,参照的这篇贴,顺便翻译下。

以basic_auth为例,首先创建如下目录结构:

basic_auth
|-- USAGE
|-- basic_auth_generator.rb
`-- templates
    |-- INSTALL
    |-- controllers
    |    `-- user_controller.rb
    |-- lib
    |    `-- basic_auth.rb
    |-- migrate
    |    `-- create_users.rb
    |-- models
    |    |-- notifications.rb
    |    `-- user.rb
    |-- test
    |    |-- fixtures
    |    |    `-- users.yml
    |    |-- functional
    |    |    `-- user_controller_test.rb
    |    `-- unit
    |        `-- user_test.rb
    `-- views
        |-- notifications
        |    `-- forgot_password.rhtml
        `-- user
            |-- change_password.rhtml
            |-- forgot_password.rhtml
            |-- hidden.rhtml
            |-- login.rhtml
            |-- signup.rhtml
            `-- welcome.rhtml

可以看到generator主要由两部分组成:

  • 一个Templates目录,保存generator的模板文件
  • 一个以generator结尾的rb文件,它负责拷贝模板文件到用户的Rails应用中,并在必要时对模板进行修改

要能够通过generate/destroy脚本调用到你的generator,basic_auth_generator.rb必须对Rails::Generator::Base进行扩展,并实现manifest方法:

class BasicAuthGenerator < Rails::Generator::Base
  def manifest
    record do |m|
      # Controller
      m.file "lib/basic_auth.rb", "lib/basic_auth.rb"
      m.file "controllers/user_controller.rb", “app/controllers/user_controller.rb"
      # Models
      m.file "models/user.rb", "app/models/user.rb"
      m.file "models/notifications.rb", "app/models/notifications.rb"
      # Tests
      m.file "test/unit/user_test.rb", "test/unit/user_test.rb"
      m.file "test/functional/user_controller_test.rb", "test/functional/user_controller_test.rb"
      m.file "test/fixtures/users.yml", "test/fixtures/users.yml"
      # Views.
      m.directory "app/views/notifications"
      m.directory "app/views/user"
      m.file "views/user/login.rhtml", "app/views/user/login.rhtml"
      m.file "views/user/signup.rhtml", "app/views/user/signup.rhtml"
      m.file "views/user/change_password.rhtml", "app/views/user/change_password.rhtml"
      m.file "views/user/forgot_password.rhtml", "app/views/user/forgot_password.rhtml"
      m.file "views/user/hidden.rhtml", "app/views/user/hidden.rhtml"
      m.file "views/user/hidden.rhtml", "app/views/user/welcome.rhtml"
      m.file "views/notifications/forgot_password.rhtml", "app/views/notifications/forgot_password.rhtml"
      m.migration_template "migrate/create_users.rb", "db/migrate"
      m.readme "INSTALL"
    end
  end
end

这段代码很直观,基本不需要解释,不过如果你的generator除了增加文件,还需要用户手动修改文件,那么你可能想在generate脚本的最后给出用户一些提示信息,下面是Restful Auth的做法:

def manifest
  recorded_session = record do |m|
    ......
  end
  action = nil
  action = $0.split("/")[1]
  case action
    when "generate"
      puts
      puts ("-" * 70)
      puts "Don't forget to:"
      puts
      puts " - add restful routes in config/routes.rb"
      puts " map.resources :#{model_controller_file_name}"
      puts " map.resource :#{controller_singular_name.singularize}"
      puts
      puts ("-" * 70)
      puts
    when "destroy"
      puts
      puts ("-" * 70)
      puts
      puts "Thanks for using restful_authentication"
      puts
      puts ("-" * 70)
      puts
    else
      puts
  end
  recorded_session
end

这将在用户调用generate/destroy脚本是分别给出一段提示。

如果你的generator需要根据用户参数动态生成代码及文件名称,那么你需要使用Rails::Generator::NamedBase来代替 Rails::Generator::Base,这会强制用户输入一个名称参数,你可以通过class_name(返回”Account”)和file_name(返回”account”)来得到用户希望创建的类名和文件名,并使用m.template来拷贝文件,m.template会在拷贝之前先使用erb来对文件进行解析,因此现在你的模板文件可能看起来是这个样子:

class <%= class_name %>Controller < ApplicationController

拷贝语句则是这个样子:

m.template "controllers/user_controller.rb", "app/controllers/#{file_name}_controller.rb"

如果以上这些还不能满足你的需求,那么建议你去现有的generator代码中学习,对于Rails来说,代码就是最好的文档。

This entry was posted in 指南. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

无觅相关文章插件,快速提升流量