diff --git a/Gemfile b/Gemfile index 23b8f9c..0b811b5 100644 --- a/Gemfile +++ b/Gemfile @@ -6,8 +6,8 @@ source "http://rubygems.org" # Add dependencies to develop your gem here. # Include everything needed to run rake, tests, features, etc. group :development do - gem "rspec", "~> 2.1.0" - gem "bundler", "~> 1.0.0" - gem "jeweler", "~> 1.5.1" + gem "rspec", ">= 2.1.0" + gem "bundler", ">= 1.0.0" + gem "jeweler", ">= 1.5.1" gem "simplecov", ">= 0" end diff --git a/README.rdoc b/README.rdoc index 315eb24..45fbe4f 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,12 +1,12 @@ = yettings -YAML settings for your Rails 3 app. +YAML settings for your Rails 3 app. == What does it do? -Yettings allows you to add a yml file to your "config" directory and you can access the values defined in the YAML in your Rails app. You can -use this to store API keys, constants, and other key/value pairs. This plugin was heavily inspired by settingslogic, with a few differences... You don't -have to add a class and point to the YML file. The Yetting class will be created dynamically and will be available to your Rails app. This plugin is also +Yettings allows you to add a yml file to your "config" directory and you can access the values defined in the YAML in your Rails app. You can +use this to store API keys, constants, and other key/value pairs. This plugin was heavily inspired by settingslogic, with a few differences... You don't +have to add a class and point to the YML file. The Yetting class will be created dynamically and will be available to your Rails app. This plugin is also more basic than settingslogic. It does not have support for dynamic setting creation... only the values in the yetting.yml will be available. == This project only supports Rails 3 and Ruby 1.9.2 @@ -14,9 +14,9 @@ more basic than settingslogic. It does not have support for dynamic setting cre There is a branch for 1.8.7, but it has not been merged into master. If you want to use it, you can reference the github location and branch in your Gemfile. See the issue tracker for more details == Known bug in YAML psych parser -This bug can cause issues loading the YAML keys when using Yettings. The workaround is to set your YAML parser to sych if your environment is currently using psych: +This bug can cause issues loading the YAML keys when using Yettings. The workaround is to set your YAML parser to sych if your environment is currently using psych: - YAML::ENGINE.yamler = "syck" + YAML::ENGINE.yamler = "syck" More info here: http://pivotallabs.com/users/mkocher/blog/articles/1692-yaml-psych-and-ruby-1-9-2-p180-here-there-be-dragons @@ -35,10 +35,10 @@ Install with Bundler ===Adding the YAML file with your key/value pairs 1. Create a YAML file inside /your_rails_app/config called yetting.yml -2. If you want to namespace your Yettings, create a YAML file inside /your_rails_app/config/yettings/ and call it whatever you want. +2. If you want to namespace your Yettings, create a YAML file inside /your_rails_app/config/yettings/ and call it whatever you want. ===YAML file content -You can define key/value pairs in the YAML file and these will be available in your app. You can set the defaults and any environment specific values. +You can define key/value pairs in the YAML file and these will be available in your app. You can set the defaults and any environment specific values. The file must contain each environment that you will use in your Rails app. Here is a sample: defaults: &defaults @@ -58,14 +58,14 @@ The file must contain each environment that you will use in your Rails app. Her production: <<: *defaults - -In the above example, you can define the key/value pair using strings, numbers, erb code, or arrays. Notice that the "api_key" in the development + +In the above example, you can define the key/value pair using strings, numbers, erb code, or arrays. Notice that the "api_key" in the development environment will override the "api_key" from defaults. ===Accessing the values in your Rails app -You simply call the Yetting class or the namespaced class and the key as a class method. For namespaced yml files, Yettings will convert the filename in -/your_rails_app/config/yettings/ to a class name and append Yetting. So if you have main.yml, then it will use MainYetting as the class name. +You simply call the Yetting class or the namespaced class and the key as a class method. For namespaced yml files, Yettings will convert the filename in +/your_rails_app/config/yettings/ to a class name and append Yetting. So if you have main.yml, then it will use MainYetting as the class name. Then you can call the key that you put in the YAML as a class method. Here are 2 examples: #/your_rails_app/config/yetting.yml in production @@ -78,7 +78,7 @@ Then you can call the key that you put in the YAML as a class method. Here are == Contributing to yettings - + * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it * Fork the project diff --git a/Rakefile b/Rakefile index 31b6879..a235292 100644 --- a/Rakefile +++ b/Rakefile @@ -20,7 +20,7 @@ Jeweler::Tasks.new do |gem| gem.email = "john.mcaliley@gmail.com" gem.authors = ["johnmcaliley"] gem.files.exclude 'test_app/**/*' - gem.files.exclude 'test_app/**/.*' + gem.files.exclude 'test_app/**/.*' end Jeweler::RubygemsDotOrgTasks.new @@ -37,7 +37,7 @@ end task :default => :spec -require 'rake/rdoctask' +require 'rdoc/task' Rake::RDocTask.new do |rdoc| version = File.exist?('VERSION') ? File.read('VERSION') : "" diff --git a/lib/yettings.rb b/lib/yettings.rb index 0ad1ee3..74b47ed 100644 --- a/lib/yettings.rb +++ b/lib/yettings.rb @@ -5,38 +5,45 @@ module Yettings class UndefinedYetting < StandardError; end + class << self def setup! find_ymls.each do |yml| create_yetting_class(yml) end end - + def find_ymls main_file = "#{Rails.root.to_s}/config/yetting.yml" yettings_main_file = File.exists?(main_file) ? [main_file] : [] yettings_namespaced_files = Dir.glob("#{Rails.root.to_s}/config/yettings/**/*.yml") yettings_main_file.concat(yettings_namespaced_files) end - + def create_yetting_class(yml_file) hash = load_yml(yml_file) klass_name = File.basename(yml_file).gsub(".yml","").camelize klass_name = "#{klass_name}Yetting" unless klass_name=="Yetting" klass = Object.const_set(klass_name,Class.new) hash.each do |key,value| - klass.define_singleton_method(key){ value } - end + @@key = key + klass.class_eval do + class << self + attr_accessor @@key.to_sym + end + end + klass.instance_variable_set("@#{key}",value) + end unless hash.nil? klass.class_eval do def self.method_missing(method_id,*args) raise UndefinedYetting, "#{method_id} is not defined in #{self.to_s}" end end end - + def load_yml(yml_file) erb = ERB.new(File.read(yml_file)).result erb.present? ? YAML.load(erb).to_hash[Rails.env] : {} end end # class << self -end \ No newline at end of file +end diff --git a/test_app/db/schema.rb b/test_app/db/schema.rb new file mode 100644 index 0000000..671c0da --- /dev/null +++ b/test_app/db/schema.rb @@ -0,0 +1,15 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 0) do + +end diff --git a/test_app/spec/yettings_spec.rb b/test_app/spec/yettings_spec.rb index 6b23fc3..3224f7d 100644 --- a/test_app/spec/yettings_spec.rb +++ b/test_app/spec/yettings_spec.rb @@ -4,54 +4,58 @@ YETTINGS_DIR = "#{Rails.root}/config/yettings" YETTING_FILE = "#{Rails.root}/config/yetting.yml" BLANK_YETTING_FILE = "#{Rails.root}/config/yettings/blank.yml" - + it "should load yettings in the rails app" do assert defined?(Yettings) end - + it "should find only default yml file if no others exist" do FileUtils.mv(YETTINGS_DIR,"#{YETTINGS_DIR}_tmp") if File.directory?(YETTINGS_DIR) Yettings.find_ymls.should eq ["#{Rails.root}/config/yetting.yml"] FileUtils.mv("#{YETTINGS_DIR}_tmp",YETTINGS_DIR) if File.directory?("#{YETTINGS_DIR}_tmp") end - + it "should find main and 3 yettings dir files" do Yettings.find_ymls.should eq ["#{Rails.root}/config/yetting.yml", "#{Rails.root}/config/yettings/blank.yml", "#{Rails.root}/config/yettings/hendrix.yml", - "#{Rails.root}/config/yettings/jimi.yml"] + "#{Rails.root}/config/yettings/jimi.yml"].sort end - + it "should find 3 yettings dir files if there is no main file" do FileUtils.mv("#{YETTING_FILE}","#{YETTING_FILE}_tmp") if File.exists?("#{YETTING_FILE}") Yettings.find_ymls.should eq ["#{Rails.root}/config/yettings/blank.yml", "#{Rails.root}/config/yettings/hendrix.yml", - "#{Rails.root}/config/yettings/jimi.yml"] + "#{Rails.root}/config/yettings/jimi.yml"] FileUtils.mv("#{YETTING_FILE}_tmp","#{YETTING_FILE}") if File.exists?("#{YETTING_FILE}_tmp") end - + it "should load the yml and return hash" do Yettings.load_yml("#{YETTING_FILE}").should eq "yetting1"=>"what", "yetting2"=>999, "yetting3"=>"this is erb", "yetting4"=>["element1", "element2"] end - + it "should continue gracefully given blank yettings file" do Yettings.load_yml("#{BLANK_YETTING_FILE}").should == {} end - + it "should create the classes and class methods" do Yettings.create_yetting_class("#{YETTING_FILE}") Yetting.yetting1.should eq "what" Yetting.yetting2.should eq 999 Yetting.yetting3.should eq "this is erb" Yetting.yetting4.should eq ["element1", "element2"] + # ability change configurations(using for test) + Yetting.yetting2 = 'hello123' + Yetting.yetting2.should eq 'hello123' end - + + it "should pass the integration test, since rails will run the initializer" do Yetting.yetting1.should eq "what" JimiYetting.yetting1.should eq "hendrix" HendrixYetting.yetting1.should eq "jimi" end - + it "should issue a warning for method_missing" do begin Yetting.whatwhat @@ -60,10 +64,10 @@ e.message.should =~ /whatwhat is not defined in Yetting/ end end - + it "should print the performance of setup method" do start = Time.now - Yettings.setup! + Yettings.setup! puts "Load time for Yettings.setup! = #{Time.now - start} seconds" end -end \ No newline at end of file +end