Rails支持多种方式的扩展,包括plugin,gem, 或者放到lib文件下等多种方式。 但是随着bundler的出现, Rails3时代我们还是写gem比较好, 方便管理。 所以下面只介绍如何制作属于自己的gem。开始之前先确保你机器了安装了git。 在我们的项目里面, 我看到在config/initializers/下有一个hash.rb文件, 是使用了一个monkey patch的方式来对Hash进行了一个扩展: class Hash def # my_reverse hash_new = Hash.new self.each {|key,value| if not hash_new.has_key?(key) then hash_new[value] = key end } return hash_new end end 像这种扩展方式不是很好, 我想把它修改为一个gem, 如果以后有其他的扩展,比如对Array,Hash等其他方法扩展,我们可以升级gem,这样就方便管理了,不至于那么混乱。 我们开始吧: gem install bundler
bundle gem ruby_extendsions
create ruby_extendsions/Gemfile create ruby_extendsions/Rakefile create ruby_extendsions/.gitignore create ruby_extendsions/ruby_extendsions.gemspec create ruby_extendsions/lib/ruby_extendsions.rb create ruby_extendsions/lib/ruby_extendsions/version.rb Initializating git repo in /Users/alex/work/mygems/test/ruby_extendsions
3. 使用Rspec进行TDD方式开发我们的代码: s.add_development_dependency "rspec"
bundle install
#spec/hash_spec.rb require File.expand_path(File.dirname(__FILE__) + '/spec_helper') describe "RubyExtend::HashExtendsions" do before(:each) do @hash1 = {:a => 1, :b => 2} end it "A hash data should not be reversed if havn't use ruby_extend " do #当没有使用我们的扩展的时候, Hash类是不应该包含hash_reverse这个方法的, 这个测试也保证了我们在扩展一个Ruby内部类的时候不会和其内部方法名冲突。 @hash1.respond_to?("hash_reverse").should eql false end it "A hash data should be reversed" do require 'ruby_extendsions' @hash1.hash_reverse.should eql({1=>:a, 2=>:b} ) end end
4. 运行测试: bundle exec rspec spec , bundle exec确保rspec是使用我们在.gemspec文件里声明的版本。 5. 实现代码: require 'ruby_extendsions/hash_extendsions' #我们今天要实现的Hash扩展 require 'ruby_extendsions/array_extendsions' #以后有可能用到对Array方法的扩展,我们就放这个文件里。
上面的代码都带注释了。 6. 发布我们的gem: # -*- encoding: utf-8 -*- Gem::Specification.new do |s| s.name = "ruby_extendsions" s.version = "0.1" s.platform = Gem::Platform::RUBY s.authors = ["blackanger"] s.email = ["blackanger.z@gmail.com"] s.homepage = "http:///gems/ruby_extendsions" s.summary = "Ruby Extendsions For Hash" s.description = "Ruby Extendsions" s.required_rubygems_version = ">= 1.3.6" s.rubyforge_project = "ruby_extendsions" s.add_development_dependency "bundler", ">= 1.0.0" s.add_development_dependency "rspec" s.files = `git ls-files`.split("\n") s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact s.require_path = 'lib' end
P.S 我的这个gem已经上传到了上面, 也上传到了github. (完整代码:http://github.com/ZhangHanDong/ruby_extend). |
|