feature-rich 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format=progress
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use --create @feature-rich
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ gem "activerecord", "~> 2.3.2"
9
+ group :development do
10
+ gem "rspec", "~> 2.3.0"
11
+ gem "sqlite3-ruby", :require => 'sqlite3'
12
+ gem "bundler", "~> 1.0.0"
13
+ gem "jeweler", "~> 1.5.2"
14
+ gem "rcov", ">= 0"
15
+ end
@@ -0,0 +1,36 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activerecord (2.3.11)
5
+ activesupport (= 2.3.11)
6
+ activesupport (2.3.11)
7
+ diff-lcs (1.1.2)
8
+ git (1.2.5)
9
+ jeweler (1.5.2)
10
+ bundler (~> 1.0.0)
11
+ git (>= 1.2.5)
12
+ rake
13
+ rake (0.8.7)
14
+ rcov (0.9.9)
15
+ rspec (2.3.0)
16
+ rspec-core (~> 2.3.0)
17
+ rspec-expectations (~> 2.3.0)
18
+ rspec-mocks (~> 2.3.0)
19
+ rspec-core (2.3.1)
20
+ rspec-expectations (2.3.0)
21
+ diff-lcs (~> 1.1.2)
22
+ rspec-mocks (2.3.0)
23
+ sqlite3 (1.3.3)
24
+ sqlite3-ruby (1.3.3)
25
+ sqlite3 (>= 1.3.3)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ activerecord (~> 2.3.2)
32
+ bundler (~> 1.0.0)
33
+ jeweler (~> 1.5.2)
34
+ rcov
35
+ rspec (~> 2.3.0)
36
+ sqlite3-ruby
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 hallelujah
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,19 @@
1
+ = feature-rich
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to feature-rich
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 hallelujah. See LICENSE.txt for
18
+ further details.
19
+
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "feature-rich"
16
+ gem.homepage = "http://github.com/hallelujah/feature-rich"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{A activerecord based selectionable feature}
19
+ gem.description = %Q{Conditional statement to chose feature in your application }
20
+ gem.email = "hery@rails-royce.org"
21
+ gem.authors = ["hallelujah"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ gem.add_development_dependency 'bundler', '>= 1.0.10'
27
+ gem.add_runtime_dependency 'activerecord', '~> 2.3.2'
28
+ end
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ require 'rspec/core'
32
+ require 'rspec/core/rake_task'
33
+ RSpec::Core::RakeTask.new(:spec) do |spec|
34
+ spec.pattern = FileList['spec/**/*_spec.rb']
35
+ end
36
+
37
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
38
+ spec.pattern = 'spec/**/*_spec.rb'
39
+ spec.rcov = true
40
+ spec.rcov_opts = [ '--exclude', 'gems', '--exclude', 'spec']
41
+ end
42
+
43
+ task :default => :spec
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "feature-rich #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,105 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{feature-rich}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["hallelujah"]
12
+ s.date = %q{2011-04-06}
13
+ s.description = %q{Conditional statement to chose feature in your application }
14
+ s.email = %q{hery@rails-royce.org}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ ".rvmrc",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "feature-rich.gemspec",
30
+ "init.rb",
31
+ "lib/feature-rich.rb",
32
+ "lib/feature-rich/config.rb",
33
+ "lib/feature-rich/engine.rb",
34
+ "lib/feature-rich/feature.rb",
35
+ "lib/feature-rich/feature_handler.rb",
36
+ "lib/feature-rich/group_feature.rb",
37
+ "lib/feature-rich/model_behaviour.rb",
38
+ "lib/feature-rich/railtie.rb",
39
+ "spec/config.rb",
40
+ "spec/config_spec.rb",
41
+ "spec/db.yml",
42
+ "spec/db/migrate/001_create_super_heros.rb",
43
+ "spec/db/migrate/002_create_features.rb",
44
+ "spec/db_helper.rb",
45
+ "spec/engine_spec.rb",
46
+ "spec/feature_handler.rb",
47
+ "spec/group_spec.rb",
48
+ "spec/helper.rb",
49
+ "spec/model_spec.rb",
50
+ "spec/spec_helper.rb"
51
+ ]
52
+ s.homepage = %q{http://github.com/hallelujah/feature-rich}
53
+ s.licenses = ["MIT"]
54
+ s.require_paths = ["lib"]
55
+ s.rubygems_version = %q{1.3.7}
56
+ s.summary = %q{A activerecord based selectionable feature}
57
+ s.test_files = [
58
+ "spec/config.rb",
59
+ "spec/config_spec.rb",
60
+ "spec/db/migrate/001_create_super_heros.rb",
61
+ "spec/db/migrate/002_create_features.rb",
62
+ "spec/db_helper.rb",
63
+ "spec/engine_spec.rb",
64
+ "spec/feature_handler.rb",
65
+ "spec/group_spec.rb",
66
+ "spec/helper.rb",
67
+ "spec/model_spec.rb",
68
+ "spec/spec_helper.rb"
69
+ ]
70
+
71
+ if s.respond_to? :specification_version then
72
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
73
+ s.specification_version = 3
74
+
75
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
76
+ s.add_runtime_dependency(%q<activerecord>, ["~> 2.3.2"])
77
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
78
+ s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
79
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
80
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
81
+ s.add_development_dependency(%q<rcov>, [">= 0"])
82
+ s.add_development_dependency(%q<bundler>, [">= 1.0.10"])
83
+ s.add_runtime_dependency(%q<activerecord>, ["~> 2.3.2"])
84
+ else
85
+ s.add_dependency(%q<activerecord>, ["~> 2.3.2"])
86
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
87
+ s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
88
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
89
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
90
+ s.add_dependency(%q<rcov>, [">= 0"])
91
+ s.add_dependency(%q<bundler>, [">= 1.0.10"])
92
+ s.add_dependency(%q<activerecord>, ["~> 2.3.2"])
93
+ end
94
+ else
95
+ s.add_dependency(%q<activerecord>, ["~> 2.3.2"])
96
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
97
+ s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
98
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
99
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
100
+ s.add_dependency(%q<rcov>, [">= 0"])
101
+ s.add_dependency(%q<bundler>, [">= 1.0.10"])
102
+ s.add_dependency(%q<activerecord>, ["~> 2.3.2"])
103
+ end
104
+ end
105
+
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'feature-rich'
2
+ # Ok let's go
3
+ config.after_initialize do
4
+ FeatureRich::Engine.load!
5
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ gem 'activerecord', '~> 2.3.2'
3
+ require 'activerecord'
4
+ require 'feature-rich/feature_handler'
5
+ require 'feature-rich/engine'
6
+ require 'feature-rich/config'
7
+ require 'feature-rich/model_behaviour'
8
+ require 'feature-rich/group_feature'
9
+ require 'feature-rich/feature'
@@ -0,0 +1,17 @@
1
+ module FeatureRich
2
+ class Config < ActiveSupport::OrderedOptions
3
+ def initialize(*args)
4
+ super(*args)
5
+ self.feature_model ||= "Feature"
6
+ end
7
+
8
+
9
+ def method_missing(name, *args)
10
+ if args.size == 1 && name.to_s !~ /=$/
11
+ super("#{name}=",*args)
12
+ else
13
+ super(name, *args)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,76 @@
1
+ require 'rubygems'
2
+ gem 'activerecord', '~> 2.3.2'
3
+ require 'activerecord'
4
+ require 'feature-rich/config'
5
+ require 'feature-rich/model_behaviour'
6
+ require 'feature-rich/group_feature'
7
+
8
+ module FeatureRich
9
+ module Engine
10
+ VALID_KEYS = [:feature_model, :feature_table, :config_file]
11
+
12
+ mattr_accessor :config, :feature_table_name, :feature_handler_table_name, :features, :groups
13
+
14
+ self.config = Config.new
15
+
16
+ self.groups = HashWithIndifferentAccess.new
17
+ self.features = Set.new
18
+
19
+
20
+ class << self # Class Proxy
21
+ def configure(conf = Config.new, &block)
22
+ conf.instance_exec(&block)
23
+ self.config.merge!(conf)
24
+ self.config.assert_valid_keys(*VALID_KEYS)
25
+ self.config
26
+ end
27
+
28
+ def run(&block)
29
+ instance_exec(&block)
30
+ bootstrap!
31
+ end
32
+
33
+ def load!
34
+ if Object.const_defined?(:Rails) && Rails.root
35
+ self.config.config_file ||= Rails.root.join('config/feature-rich.rb').to_s
36
+ end
37
+ run do
38
+ eval(File.read(self.config.config_file))
39
+ end
40
+ end
41
+
42
+ def feature(name, options = {})
43
+ group(:_none_) do
44
+ feature name, options
45
+ end
46
+ end
47
+
48
+ def group(name, opts = {}, &block)
49
+ group = (self.groups[name.to_sym] || FeatureRich::GroupFeature.new(name, opts)).configure(&block)
50
+ self.features += group.sets
51
+ self.groups[name.to_sym] = group
52
+ end
53
+
54
+ private
55
+
56
+ def bootstrap!
57
+ set_feature_table_name
58
+ set_feature_handler_table_name
59
+ ActiveRecord::Base.__send__ :include, FeatureRich::ModelBehaviour
60
+ end
61
+
62
+ def set_feature_handler_table_name
63
+ feature_table_name = config.feature_table || table_name(config.feature_model)
64
+ end
65
+
66
+ def set_feature_table_name
67
+ feature_table_name = config.feature_table || table_name(config.feature_model)
68
+ end
69
+
70
+ def table_name(name)
71
+ ActiveRecord::Base.__send__ :undecorated_table_name, name
72
+ end
73
+ end # Class Proxy
74
+
75
+ end
76
+ end
@@ -0,0 +1,42 @@
1
+ module FeatureRich
2
+ FeatureStruct = Struct.new(:features, :group_features)
3
+ FeatureStruct.class_eval do
4
+ def initialize(f,g)
5
+ self.features = []
6
+ self.group_features = []
7
+ super
8
+ end
9
+
10
+ def modify(ary)
11
+ self.features = ary.grep(Symbol)
12
+ self.group_features = ary.grep(GroupFeature){|g| g.name.to_sym }
13
+ end
14
+
15
+ def self.default
16
+ new([],[])
17
+ end
18
+ end
19
+
20
+ class Feature < ActiveRecord::Base
21
+ belongs_to :featured, :polymorphic => true
22
+ serialize :content, FeatureStruct
23
+
24
+ before_save :symbolize_feature_name
25
+
26
+ def after_initialize
27
+ self.content ||= FeatureStruct.default
28
+ end
29
+
30
+ def modify(ary)
31
+ content_will_change!
32
+ content.modify(ary)
33
+ end
34
+
35
+ protected
36
+
37
+ def symbolize_feature_name
38
+ content.features.map!(&:to_sym)
39
+ content.group_features.map!(&:to_sym)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ module FeatureRich
2
+ class FeatureHandler
3
+
4
+ attr_reader :name
5
+ attr_accessor :label, :disabled
6
+
7
+ def initialize(name, options = {})
8
+ @name = name.to_sym
9
+ @label = options[:label]
10
+ @disabled = !! options[:disabled]
11
+ end
12
+
13
+ def disabled?
14
+ !! @disabled
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ module FeatureRich
2
+ class GroupFeature < FeatureRich::FeatureHandler
3
+
4
+ attr_accessor :sets
5
+
6
+ def initialize(group_name, options = {})
7
+ super
8
+ @sets = []
9
+ end
10
+
11
+ def subset?(ary)
12
+ (names & ary) == names
13
+ end
14
+
15
+ def names
16
+ sets.map(&:name)
17
+ end
18
+
19
+ def feature(name, options = {})
20
+ sets << FeatureRich::FeatureHandler.new(name.to_sym, options)
21
+ end
22
+
23
+ def configure(&block)
24
+ instance_exec(&block)
25
+ self
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,56 @@
1
+ module FeatureRich
2
+ module ModelBehaviour
3
+
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end # self.included
7
+
8
+ module ClassMethods
9
+ def has_feature
10
+ has_one :feature, :as => :featured, :class_name => "FeatureRich::Feature", :autosave => true
11
+ include InstanceMethods
12
+ end
13
+ end # ClassMethods
14
+
15
+ module InstanceMethods
16
+
17
+ def features
18
+ _feature.content
19
+ end
20
+
21
+ def features=(ary)
22
+ _feature.modify(ary)
23
+ end
24
+
25
+ def has_feature?(feature, options = {})
26
+ with_group(feature, options[:group]) do |f|
27
+ case f
28
+ when Symbol, String
29
+ features.features.include?(f.to_sym)
30
+ when GroupFeature
31
+ f.disabled? || f.subset?(features.features) || features.group_features.include?(f.name)
32
+ when FeatureHandler
33
+ f.disabled? || features.features.include?(f.name)
34
+ end
35
+ end
36
+ end
37
+
38
+ protected
39
+
40
+ def _feature
41
+ (feature || build_feature(:content => FeatureStruct.default))
42
+ end
43
+
44
+ def with_group(fname, with)
45
+ if with
46
+ feature = FeatureRich::Engine.groups[fname]
47
+ else
48
+ feature = FeatureRich::Engine.features.find{|f| f.name == fname} || fname
49
+ end
50
+ yield(feature) || false
51
+ end
52
+
53
+ end # InstanceMethods
54
+
55
+ end
56
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails'
2
+ require 'feature-rich'
3
+ module FeatureRich
4
+ class Railtie < Rails::Railtie
5
+
6
+ config.feature_rich = FeatureRich::Engine.config
7
+ config.feature_rich.config_file = Rails.root.join('config/feature-rich.rb').to_s
8
+
9
+ initializer "feature-rich.after_initialize" do |app|
10
+ FeatureRich::Engine.run do
11
+ eval(File.read(app.config.feature_rich.config_file))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ group :color do
2
+ feature :red
3
+ feature :blue
4
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "FeatureRich::Config instance" do
4
+ before do
5
+ @config = FeatureRich::Config.new
6
+ end
7
+
8
+ it "should return \"Feature\" as default feature_model" do
9
+ @config.feature_model.should == "Feature"
10
+ end
11
+
12
+ it "should pass arguments like standard method" do
13
+ @config.feature_model "OtherModel"
14
+ @config.feature_model.should == "OtherModel"
15
+ end
16
+
17
+ end
@@ -0,0 +1,11 @@
1
+ base: &BASE
2
+ adapter: sqlite3
3
+ database: development.sqlite3
4
+ pool: 5
5
+ timeout: 5000
6
+
7
+ development:
8
+ <<: *BASE
9
+
10
+ test:
11
+ <<: *BASE
@@ -0,0 +1,12 @@
1
+ class CreateSuperHeros < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ create_table :super_heros do |t|
5
+ t.string :name
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :super_heros
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ class CreateFeatures < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :features do |t|
4
+ t.text :content
5
+ t.string :featured_type
6
+ t.string :featured_id
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :features
12
+ end
13
+ end
@@ -0,0 +1,85 @@
1
+ # Extracted from rails-2.3.5/railties/lib/tasks/databases.rake
2
+ require 'erb'
3
+ def create_database(config)
4
+ begin
5
+ if config['adapter'] =~ /sqlite/
6
+ if File.exist?(config['database'])
7
+ $stderr.puts "#{config['database']} already exists"
8
+ else
9
+ begin
10
+ # Create the SQLite database
11
+ ActiveRecord::Base.establish_connection(config)
12
+ ActiveRecord::Base.connection
13
+ rescue
14
+ $stderr.puts $!, *($!.backtrace)
15
+ $stderr.puts "Couldn't create database for #{config.inspect}"
16
+ end
17
+ end
18
+ return # Skip the else clause of begin/rescue
19
+ else
20
+ ActiveRecord::Base.establish_connection(config)
21
+ ActiveRecord::Base.connection
22
+ end
23
+ rescue
24
+ case config['adapter']
25
+ when 'mysql'
26
+ @charset = ENV['CHARSET'] || 'utf8'
27
+ @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
28
+ begin
29
+ ActiveRecord::Base.establish_connection(config.merge('database' => nil))
30
+ ActiveRecord::Base.connection.create_database(config['database'], :charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation))
31
+ ActiveRecord::Base.establish_connection(config)
32
+ rescue
33
+ $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation} (if you set the charset manually, make sure you have a matching collation)"
34
+ end
35
+ when 'postgresql'
36
+ @encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
37
+ begin
38
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
39
+ ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
40
+ ActiveRecord::Base.establish_connection(config)
41
+ rescue
42
+ $stderr.puts $!, *($!.backtrace)
43
+ $stderr.puts "Couldn't create database for #{config.inspect}"
44
+ end
45
+ end
46
+ else
47
+ $stderr.puts "#{config['database']} already exists"
48
+ end
49
+ end
50
+
51
+ def drop_database(config)
52
+ case config['adapter']
53
+ when 'mysql'
54
+ ActiveRecord::Base.establish_connection(config)
55
+ ActiveRecord::Base.connection.drop_database config['database']
56
+ when /^sqlite/
57
+ FileUtils.rm(File.join(MyROOT, config['database']))
58
+ when 'postgresql'
59
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
60
+ ActiveRecord::Base.connection.drop_database config['database']
61
+ end
62
+ end
63
+
64
+ config = YAML.load(ERB.new(IO.read(File.expand_path( '../db.yml',__FILE__ ))).result(binding))
65
+ ActiveRecord::Base.configurations = config.with_indifferent_access
66
+ ActiveRecord::Base.establish_connection :development
67
+
68
+ logfile = File.open(File.expand_path('../log/database.log',__FILE__), 'a')
69
+ logfile.sync = true
70
+ ActiveRecord::Base.logger = Logger.new(logfile)
71
+
72
+ def migrate!(config)
73
+ migrator = ActiveRecord::Migrator.new(:up,File.expand_path('../db/migrate',__FILE__),nil)
74
+ #if ! migrator.pending_migrations.blank? || ENV['REMIGRATE']
75
+ # Drop database
76
+ drop_database(config)
77
+ # Create database
78
+ create_database(config)
79
+ # Migrate up
80
+ puts "Migrate up"
81
+ ActiveRecord::Migrator.migrate(File.expand_path('../db/migrate',__FILE__),nil)
82
+ # end
83
+ end
84
+
85
+ migrate!(config['development'])
@@ -0,0 +1,113 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe FeatureRich::Engine do
4
+ before do
5
+ FeatureRich::Engine.config.clear
6
+ FeatureRich::Engine.groups.clear
7
+ FeatureRich::Engine.features.clear
8
+ end
9
+
10
+ it "should require activerecord" do
11
+ lambda{ActiveRecord::Base}.should_not raise_exception
12
+ end
13
+
14
+ it "should declare FeatureRich::Config" do
15
+ lambda{FeatureRich::Config}.should_not raise_exception
16
+ end
17
+
18
+ it "should respond to #configure" do
19
+ should respond_to(:configure).with(1)
20
+ end
21
+
22
+ it "shoud respond to #config" do
23
+ should respond_to(:config)
24
+ FeatureRich::Engine.config.should be_an_instance_of(FeatureRich::Config)
25
+ end
26
+
27
+ it "should return a FeatureRich::Config instance when invoking #configure" do
28
+ FeatureRich::Engine.configure{}.should be_an_instance_of FeatureRich::Config
29
+ end
30
+
31
+ it "should invoke #instance_exec on FeatureRich::Config when invoking #configure" do
32
+ lambda do
33
+ @config = FeatureRich::Config.new
34
+ @config.should_receive(:instance_exec).once
35
+ @config.stub!(:feature_model).and_return("Feature")
36
+ FeatureRich::Engine.config.should_receive(:merge!).once
37
+ FeatureRich::Engine.configure(@config) do
38
+ feature_model = "Feature"
39
+ end
40
+ end.should_not raise_exception
41
+ end
42
+
43
+ it "should respond to #run" do
44
+ should respond_to(:run)
45
+ FeatureRich::Engine.should_receive(:bootstrap!).once
46
+ FeatureRich::Engine.run do
47
+ configure do
48
+ feature_model "OtherModel"
49
+ config_file File.expand_path('../config.yml',__FILE__)
50
+ end
51
+ end
52
+ end
53
+
54
+ it "should define VALID_KEYS constant" do
55
+ FeatureRich::Engine.const_defined?(:VALID_KEYS).should be_true
56
+ FeatureRich::Engine::VALID_KEYS.should =~ [:feature_table, :feature_model, :config_file]
57
+ end
58
+
59
+ it "should raise ArgumentError on bad options " do
60
+ lambda do
61
+ FeatureRich::Engine.run do
62
+ configure do
63
+ bad_option "Hello"
64
+ end
65
+ end
66
+ end.should raise_exception(ArgumentError)
67
+ end
68
+
69
+ it "should respond to #features" do
70
+ FeatureRich::Engine.should respond_to(:features)
71
+ FeatureRich::Engine.features.should == Set.new
72
+ end
73
+
74
+ it "should respond to #groups" do
75
+ FeatureRich::Engine.should respond_to(:groups)
76
+ FeatureRich::Engine.groups.should == HashWithIndifferentAccess.new
77
+ end
78
+
79
+ it "should respond to #feature" do
80
+ FeatureRich::Engine.should respond_to(:feature).with(1)
81
+ FeatureRich::Engine.feature(:fly)
82
+ FeatureRich::Engine.features.map(&:name).should include(:fly)
83
+ FeatureRich::Engine.groups.should include(:_none_)
84
+ FeatureRich::Engine.groups[:_none_].sets.map(&:name).should =~ [:fly]
85
+ end
86
+
87
+ it "should respond to #group" do
88
+ FeatureRich::Engine.should respond_to(:feature).with(1)
89
+ group_feature = mock('FeatureRich::GroupFeature')
90
+ FeatureRich::Engine.groups.should_receive(:[]=).once.with(:masked,anything)
91
+ FeatureRich::Engine.groups.should_receive(:[]).once
92
+ FeatureRich::Engine.should_receive(:features=).once
93
+ FeatureRich::Engine.should_receive(:features).once.and_return(Set.new)
94
+ FeatureRich::Engine.group(:masked) do
95
+ feature :black_color
96
+ feature :full_face
97
+ end
98
+ end
99
+
100
+ it "should respond to load!" do
101
+ FeatureRich::Engine.should respond_to(:load!)
102
+ Rails = mock('hello')
103
+ root = mock('root')
104
+ root.stub!(:join).and_return(File.expand_path('../config.rb',__FILE__))
105
+ Rails.stub!(:root).and_return(root)
106
+ FeatureRich::Engine.load!
107
+ FeatureRich::Engine.groups.should have_key(:color)
108
+ FeatureRich::Engine.features.should_not be_empty
109
+ FeatureRich::Engine.features.should satisfy{|set| set.all?{ |n| FeatureRich::FeatureHandler === n} }
110
+ FeatureRich::Engine.features.map(&:name).to_a.should =~ [ :red,:blue ]
111
+ end
112
+
113
+ end
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ describe FeatureRich::FeatureHandler do
3
+ it "should define a instance attribute reader :name" do
4
+ @group.should respond_to(:name)
5
+ @group.name.should be_an_instance_of(Symbol)
6
+ end
7
+
8
+
9
+ it "should respond to #new with a name" do
10
+ FeatureRich::GroupFeature.should respond_to(:new).with(1)
11
+ end
12
+
13
+ it "should be labeled" do
14
+ lambda do
15
+ @handler = FeatureRich::FeatureHandler.new(:a_handler, :label => "This handler")
16
+ end.should_not raise_exception
17
+ @handler.should respond_to(:label)
18
+
19
+ @handler.label.should == 'This handler'
20
+ @handler.should respond_to(:label=)
21
+
22
+ @handler.label = 'Other handler'
23
+ @handler.label.should == 'Other handler'
24
+ end
25
+
26
+ it "should be disabled" do
27
+ handler = FeatureRich::GroupFeature.new(:a_handler, :disabled => true)
28
+ handler.disabled?.should be_true
29
+
30
+ handler = FeatureRich::GroupFeature.new(:a_handler, :disabled => false)
31
+ handler.disabled?.should be_false
32
+
33
+ handler.disabled = true
34
+ handler.disabled?.should be_true
35
+ end
36
+
37
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ describe FeatureRich::GroupFeature do
3
+
4
+ before do
5
+ @group = FeatureRich::GroupFeature.new(:a_group)
6
+ end
7
+
8
+ it "should define instance attribute accessor :sets" do
9
+ @group.should respond_to(:sets)
10
+ @group.should respond_to(:sets=)
11
+ @group.sets.should == Array.new
12
+ end
13
+
14
+ it "should respond to #configure" do
15
+ @group.should respond_to(:configure).with(0)
16
+ lambda do
17
+ @group.configure do
18
+ feature :black_color
19
+ feature :full_face
20
+ end
21
+ end.should_not raise_exception
22
+ end
23
+
24
+ it "should respond to #subset?" do
25
+ @group.should respond_to(:subset?)
26
+ @group.configure do
27
+ feature :red
28
+ feature :blue
29
+ feature :green
30
+ end
31
+ @group.subset?([:red, :green, :blue, :orange]).should be_true
32
+ @group.subset?([:red, :black]).should be_false
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ logfile = File.open(File.expand_path('../log/database.log',__FILE__), 'a')
3
+ logfile.sync = true
4
+ require 'active_record/fixtures'
5
+ ActiveRecord::Base.logger = Logger.new(logfile)
6
+ migrator = ActiveRecord::Migrator.new(:up,File.expand_path('../db/migrate',__FILE__),nil)
7
+
8
+ if ! migrator.pending_migrations.blank? || ENV['REMIGRATE']
9
+ ActiveRecord::Base.connection.execute("DROP DATABASE gettext_column_mapping")
10
+ ActiveRecord::Base.connection.execute("CREATE DATABASE gettext_column_mapping")
11
+ ActiveRecord::Base.establish_connection(:test)
12
+
13
+ class ActiveRecord::Migration
14
+ def self.load_data(filename, dir = File.expand_path('../db/fixtures',__FILE__))
15
+ Fixtures.create_fixtures(dir, filename)
16
+ end
17
+ end
18
+
19
+ # Migrate up
20
+ puts "Migrate up"
21
+ ActiveRecord::Migrator.migrate(File.expand_path('../db/migrate',__FILE__),nil)
22
+ end
23
+ $gettext_column_mapping_root = File.dirname(__FILE__)
24
+ FileUtils.mkdir_p(File.join($gettext_column_mapping_root,'locale'))
@@ -0,0 +1,114 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/db_helper')
3
+
4
+ describe FeatureRich::ModelBehaviour do
5
+ # Called once
6
+ before(:all) do
7
+ FeatureRich::Engine.run do
8
+ configure do
9
+ feature_model "Feature"
10
+ end
11
+ end
12
+ SuperHero = Class.new(ActiveRecord::Base)
13
+ SuperHero.has_feature
14
+ end
15
+
16
+ # Called before each test
17
+ before do
18
+ FeatureRich::Engine.config.clear
19
+ FeatureRich::Engine.features.clear
20
+ FeatureRich::Engine.groups.clear
21
+ @superman = SuperHero.new
22
+ @superman.should be_an_instance_of SuperHero
23
+ @superman.new_record?.should be_true
24
+ end
25
+
26
+ it "should create a has_many polymorphic relation" do
27
+ SuperHero.reflections[:feature].should_not be_nil
28
+ SuperHero.reflections[:feature].macro.should == :has_one
29
+ SuperHero.reflections[:feature].options[:as].should == :featured
30
+ SuperHero.reflections[:feature].options[:autosave].should be_true
31
+ end
32
+
33
+ it "should respond to #features" do
34
+ g = FeatureRich::GroupFeature.new(:flying)
35
+ FeatureRich::Engine.run do
36
+ group :flying do
37
+ feature :wings
38
+ end
39
+ end
40
+ @superman.should respond_to(:features)
41
+ @superman.features.should == FeatureRich::FeatureStruct.default
42
+ @superman.features = [:fly]
43
+ @superman.features.features.should == [:fly]
44
+ @superman.feature.should be_an_instance_of FeatureRich::Feature
45
+ @superman.feature.new_record?.should be_true
46
+ @superman.name = "Clark Kent"
47
+ @superman.save!
48
+ @superman.reload
49
+ @superman.feature.should be_an_instance_of FeatureRich::Feature
50
+ @superman.features.features.should == [:fly]
51
+ @superman.features.group_features.should be_empty
52
+ @superman.features = [:strong, g]
53
+ @superman.changed?.should be_false
54
+ @superman.save!
55
+ @superman.reload
56
+ @superman.features.features.should == [:strong]
57
+ @superman.features.group_features.should == [:flying]
58
+ end
59
+
60
+ it "should respond to #has_feature?" do
61
+ @superman.should respond_to(:has_feature?)
62
+ @superman.has_feature?(:fly).should be_false
63
+ @superman.features = [:fly]
64
+ @superman.has_feature?(:fly).should be_true
65
+
66
+ group = FeatureRich::GroupFeature.new(:flying)
67
+ # Mocking is more convenient
68
+ group.should_receive(:subset?).twice.and_return(false,true)
69
+ @superman.has_feature?(group).should be_false
70
+ @superman.has_feature?(group).should be_true
71
+ end
72
+
73
+ it "should respond to #has_feature? with option group" do
74
+ g = FeatureRich::GroupFeature.new(:flying)
75
+ FeatureRich::Engine.run do
76
+ group :flying do
77
+ feature :wings
78
+ end
79
+ group :singing do
80
+ feature :voice
81
+ end
82
+ end
83
+ @superman.features = [:fly, g ]
84
+ @superman.features.group_features.should == [:flying]
85
+ @superman.has_feature?(:flying, :group => true).should be_true
86
+ @superman.has_feature?(:singing, :group => true).should be_false
87
+ end
88
+
89
+ it "should have feature if group is disabled" do
90
+ g = FeatureRich::GroupFeature.new(:flying, :disabled => true)
91
+ FeatureRich::Engine.run do
92
+ group :flying do
93
+ feature :wings
94
+ end
95
+ group :singing do
96
+ feature :voice
97
+ end
98
+ end
99
+ @superman.features = [:fly, g ]
100
+ @superman.features.group_features.should == [:flying]
101
+ @superman.has_feature?(:flying, :group => true).should be_true
102
+ end
103
+
104
+ it "should have feature if Feature is disabled" do
105
+ FeatureRich::Engine.run do
106
+ feature :wings
107
+ feature :voice, :disabled => true
108
+ end
109
+ @superman.features = [:fly ]
110
+ @superman.features.features.should == [:fly]
111
+ @superman.has_feature?(:voice).should be_true
112
+ end
113
+
114
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ MyROOT = File.expand_path('../../',__FILE__)
4
+ require 'rspec'
5
+ require 'feature-rich'
6
+
7
+ # Requires supporting files with custom matchers and macros, etc,
8
+ # in ./support/ and its subdirectories.
9
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
10
+
11
+ RSpec.configure do |config|
12
+
13
+ end
metadata ADDED
@@ -0,0 +1,231 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: feature-rich
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - hallelujah
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-06 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ hash: 7
28
+ segments:
29
+ - 2
30
+ - 3
31
+ - 2
32
+ version: 2.3.2
33
+ requirement: *id001
34
+ prerelease: false
35
+ type: :runtime
36
+ name: activerecord
37
+ - !ruby/object:Gem::Dependency
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 2
46
+ - 3
47
+ - 0
48
+ version: 2.3.0
49
+ requirement: *id002
50
+ prerelease: false
51
+ type: :development
52
+ name: rspec
53
+ - !ruby/object:Gem::Dependency
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirement: *id003
64
+ prerelease: false
65
+ type: :development
66
+ name: sqlite3-ruby
67
+ - !ruby/object:Gem::Dependency
68
+ version_requirements: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ hash: 23
74
+ segments:
75
+ - 1
76
+ - 0
77
+ - 0
78
+ version: 1.0.0
79
+ requirement: *id004
80
+ prerelease: false
81
+ type: :development
82
+ name: bundler
83
+ - !ruby/object:Gem::Dependency
84
+ version_requirements: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ hash: 7
90
+ segments:
91
+ - 1
92
+ - 5
93
+ - 2
94
+ version: 1.5.2
95
+ requirement: *id005
96
+ prerelease: false
97
+ type: :development
98
+ name: jeweler
99
+ - !ruby/object:Gem::Dependency
100
+ version_requirements: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ requirement: *id006
110
+ prerelease: false
111
+ type: :development
112
+ name: rcov
113
+ - !ruby/object:Gem::Dependency
114
+ version_requirements: &id007 !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 1
122
+ - 0
123
+ - 10
124
+ version: 1.0.10
125
+ requirement: *id007
126
+ prerelease: false
127
+ type: :development
128
+ name: bundler
129
+ - !ruby/object:Gem::Dependency
130
+ version_requirements: &id008 !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ~>
134
+ - !ruby/object:Gem::Version
135
+ hash: 7
136
+ segments:
137
+ - 2
138
+ - 3
139
+ - 2
140
+ version: 2.3.2
141
+ requirement: *id008
142
+ prerelease: false
143
+ type: :runtime
144
+ name: activerecord
145
+ description: "Conditional statement to chose feature in your application "
146
+ email: hery@rails-royce.org
147
+ executables: []
148
+
149
+ extensions: []
150
+
151
+ extra_rdoc_files:
152
+ - LICENSE.txt
153
+ - README.rdoc
154
+ files:
155
+ - .document
156
+ - .rspec
157
+ - .rvmrc
158
+ - Gemfile
159
+ - Gemfile.lock
160
+ - LICENSE.txt
161
+ - README.rdoc
162
+ - Rakefile
163
+ - VERSION
164
+ - feature-rich.gemspec
165
+ - init.rb
166
+ - lib/feature-rich.rb
167
+ - lib/feature-rich/config.rb
168
+ - lib/feature-rich/engine.rb
169
+ - lib/feature-rich/feature.rb
170
+ - lib/feature-rich/feature_handler.rb
171
+ - lib/feature-rich/group_feature.rb
172
+ - lib/feature-rich/model_behaviour.rb
173
+ - lib/feature-rich/railtie.rb
174
+ - spec/config.rb
175
+ - spec/config_spec.rb
176
+ - spec/db.yml
177
+ - spec/db/migrate/001_create_super_heros.rb
178
+ - spec/db/migrate/002_create_features.rb
179
+ - spec/db_helper.rb
180
+ - spec/engine_spec.rb
181
+ - spec/feature_handler.rb
182
+ - spec/group_spec.rb
183
+ - spec/helper.rb
184
+ - spec/model_spec.rb
185
+ - spec/spec_helper.rb
186
+ has_rdoc: true
187
+ homepage: http://github.com/hallelujah/feature-rich
188
+ licenses:
189
+ - MIT
190
+ post_install_message:
191
+ rdoc_options: []
192
+
193
+ require_paths:
194
+ - lib
195
+ required_ruby_version: !ruby/object:Gem::Requirement
196
+ none: false
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ hash: 3
201
+ segments:
202
+ - 0
203
+ version: "0"
204
+ required_rubygems_version: !ruby/object:Gem::Requirement
205
+ none: false
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ hash: 3
210
+ segments:
211
+ - 0
212
+ version: "0"
213
+ requirements: []
214
+
215
+ rubyforge_project:
216
+ rubygems_version: 1.3.7
217
+ signing_key:
218
+ specification_version: 3
219
+ summary: A activerecord based selectionable feature
220
+ test_files:
221
+ - spec/config.rb
222
+ - spec/config_spec.rb
223
+ - spec/db/migrate/001_create_super_heros.rb
224
+ - spec/db/migrate/002_create_features.rb
225
+ - spec/db_helper.rb
226
+ - spec/engine_spec.rb
227
+ - spec/feature_handler.rb
228
+ - spec/group_spec.rb
229
+ - spec/helper.rb
230
+ - spec/model_spec.rb
231
+ - spec/spec_helper.rb