provision 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## v0.0.1
2
+
3
+ * initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in provision.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Chen Fisher
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # Provision
2
+
3
+ The provision gem lets you hook a provision filter to a method. **ANY method**.
4
+
5
+ For example,
6
+ Lets say we have an article website, where users can post articles.
7
+
8
+ We want to limit the number of articles a user can post to our website, based on a primium account. For example, if the user is using the free version he can post up to 5 articles, when a user that has paid and is using the pro account, can post up to 20 articles.
9
+
10
+ This is where 'provision' comes in. It makes it easy and dry to do provisions on your website.
11
+
12
+ The great thing about **provision** is that it can act on any level - model, controller or any other class you have.
13
+ Think of it as ActiveRecord's **validate** and Controller's **before_filter** combined and available on any class and method.
14
+
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ gem 'provision'
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install provision
29
+
30
+ ## Usage
31
+ When a method is provisioned, whenever it is called, the provision method comes into action.
32
+ If the provision method returns true then the original method will be called. If the provision returns false
33
+ then the method won't be called (and false will be returned)
34
+
35
+ ### Provision using a method
36
+ class SomeClass
37
+ def a_method
38
+ # do something
39
+ end
40
+ provision :a_method, :with => :provision_method
41
+
42
+ private
43
+ def provision_method
44
+ # some condition (returns true or false)
45
+ end
46
+ end
47
+
48
+ **provision_method** can take optional ***args** which are the arguments passed to the original method:
49
+
50
+ def provision_method(*args)
51
+ # some condition using args
52
+ end
53
+
54
+
55
+ ### Provision using a proc (lambda)
56
+ class SomeClass
57
+ def a_method
58
+ # do something
59
+ end
60
+ provision :a_method, :with => lambda{ [some condition] }
61
+ end
62
+
63
+ **lambda** can take arguments like so:
64
+
65
+ provision :a_method, :with => lambda{ |sender, *args| [some condition] }
66
+ where **sender** is the instance of SomeClass and ***args** are the arguments passed to the original method
67
+
68
+
69
+ ### Provision using a class name
70
+ class SomeClass
71
+ def a_method
72
+ # do something
73
+ end
74
+ provision :a_method, :with => ProvisionClass
75
+ end
76
+
77
+ **NOTE**: provision will try to call `ProvisionClass.provision!` (a class method); if the class does not respond to provision! then
78
+ it will create an instance of ProvisionClass and then call `provision!` (mind the bang!)
79
+
80
+ class ProvisionClass
81
+ def self.provision!(sender, *args)
82
+ # some condition using sender and *args
83
+ end
84
+ end
85
+
86
+ **sender** is the instance of SomeClass and ***args** are the arguments passed to the original method
87
+
88
+ ### Provision using an instance of a class
89
+ when the **lambda** block return something other than *true* or *false* then provision assumes it returns an instance
90
+ of a class that responds to **provision!**
91
+
92
+ provision :a_method, :with => lambda{ |sender, *args| ProvisionClass.new(sender, *args) }
93
+
94
+ **sender** and ***args** are optional
95
+
96
+ ### Add a block to do something
97
+ You can add a block which will be called when the provision returns false.
98
+
99
+ provision :a_method, :with => lambda{ some_condition } do |sender, *args|
100
+ # do something for when the provision fails
101
+ # for example: send a notification email to the user you just provisioned
102
+ end
103
+
104
+ **sender** and ***args** are optional
105
+
106
+ ### Provision more than one method at a time
107
+ You can pass any number of methods to be provisioned
108
+
109
+ provision :a_method, :another_method, :with => lambda{ some_condition } do
110
+ # do something
111
+ end
112
+
113
+ ### Use it in your controllers and models
114
+ You can use it in your controllers and models like you use before_filter and validations.
115
+ Lets provision a user on the number of posts they can post. We can do this on the controller level or on the model level:
116
+
117
+ #### Controller level example:
118
+ class PostsController < ApplicationController
119
+ include provision
120
+
121
+ def create
122
+ # create the post
123
+ end
124
+
125
+ provision :create, :with => UserProvision do |controller|
126
+ controller.flash[:error] = "You have maxed out your posts"
127
+ redirect_to some_url
128
+ end
129
+ end
130
+
131
+ class UserProvision
132
+ def self.provision!(controller)
133
+ controller.current_user.post_count < MAX_POSTS
134
+ end
135
+ end
136
+
137
+ #### Model level example:
138
+ class Post < ActiveRecord::Base
139
+ include provision
140
+
141
+ provision :save, :valid?, :with => lambda{ |post| post.user.post_count < MAX_COUNT } do |post|
142
+ post.errors[:count] = "you have maxed out you post count"
143
+ false
144
+ end
145
+ end
146
+
147
+ ## GOTCHA!
148
+ `provision` call **must** come **after** your provisioned method definitions
149
+
150
+
151
+ ## Contributing
152
+
153
+ 1. Fork it
154
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
155
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
156
+ 4. Push to the branch (`git push origin my-new-feature`)
157
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,3 @@
1
+ module Provision
2
+ VERSION = "0.0.1"
3
+ end
data/lib/provision.rb ADDED
@@ -0,0 +1,94 @@
1
+ require "provision/version"
2
+
3
+ module Provision
4
+ module ClassMethods
5
+
6
+ ##
7
+ #
8
+ def provision(*args, &block)
9
+ options = args.last.is_a?(::Hash) ? args.pop : {}
10
+
11
+ hook(*args, :before => options[:with], &block)
12
+ end
13
+
14
+ ##
15
+ # hooks the specified array of methods to a method specified with the :before hook
16
+ # calls the original method only if the hooked method returns true
17
+ # usage:
18
+ # hook :method1, :method2, :before => :method_name
19
+ def hook(*args, &block)
20
+ hooks = args.last.is_a?(::Hash) ? args.pop : {}
21
+
22
+ args.each do |method|
23
+ original_method = self.instance_method(method)
24
+
25
+ self.send(:define_method, method) do |*a|
26
+ return original_method.bind(self).call(*a) if
27
+ case
28
+ when hooks[:before].is_a?(Symbol)
29
+ hook_method(hooks[:before], *a)
30
+ when hooks[:before].is_a?(Class)
31
+ hook_class(hooks[:before], *a)
32
+ when hooks[:before].is_a?(Proc)
33
+ hook_proc(hooks[:before], *a)
34
+ when hooks[:before].instance_of?(hooks[:before].class)
35
+ hook_instance(hooks[:before], *a)
36
+ end
37
+
38
+ if block_given?
39
+ if block.arity == 0
40
+ return yield
41
+ else
42
+ return yield(self, *a)
43
+ end
44
+ end
45
+
46
+ false
47
+ end
48
+ end
49
+ end
50
+
51
+ private :hook
52
+ end
53
+
54
+ module InstanceMethods
55
+ def hook_method(h, *a)
56
+ self.send(h, *a)
57
+ end
58
+
59
+ def hook_class(h, *a)
60
+ if h.respond_to? :provision!
61
+ h.provision!(self, *a)
62
+ else
63
+ h.new.provision!(self, *a)
64
+ end
65
+ end
66
+
67
+ def hook_instance(h, *a)
68
+ h.provision!(self, *a)
69
+ end
70
+
71
+ def hook_proc(h, *a)
72
+ # call the proc
73
+ if h.arity == 0
74
+ result = h.call
75
+ else
76
+ result = h.call(self, *a)
77
+ end
78
+
79
+ # if proc returns true or false then return the result
80
+ return result if result == true || result == false
81
+
82
+ # if proc returns an instance of an object then call provision! on it
83
+ result.provision!(*a)
84
+ end
85
+
86
+ private :hook_method, :hook_class, :hook_instance, :hook_proc
87
+
88
+ end
89
+
90
+ def self.included(receiver)
91
+ receiver.extend ClassMethods
92
+ receiver.send :include, InstanceMethods
93
+ end
94
+ end
data/provision.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'provision/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "provision"
8
+ gem.version = Provision::VERSION
9
+ gem.authors = ["Chen Fisher"]
10
+ gem.email = ["chen.fisher@gmail.com"]
11
+ gem.description = %q{Lets one hook a provision for a method}
12
+ gem.summary = %q{When a method is provisioned, any call to that method is passed through a provision filter that can stop the method execution and perform some actions}
13
+ gem.homepage = "https://github.com/chenfisher/provision"
14
+
15
+ gem.add_development_dependency "rspec"
16
+
17
+ gem.files = `git ls-files`.split($/)
18
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
+ gem.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,3 @@
1
+ class Sample
2
+ include Provision
3
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'provision/sample'
3
+
4
+ describe Provision do
5
+
6
+ before :each do
7
+ @sample = Sample.new
8
+ @sample.stub(:a_method).and_return('hello')
9
+ @meta = class << @sample; self; end
10
+ end
11
+
12
+ it "should call the method if provision returns true" do
13
+ @sample.stub(:this_method).and_return(true)
14
+ @meta.provision :a_method, :with => :this_method
15
+
16
+ @sample.a_method.should eq 'hello'
17
+ end
18
+
19
+ it "should provision a method using a method name" do
20
+ @sample.stub(:this_method).and_return(false)
21
+ @meta.provision :a_method, :with => :this_method
22
+
23
+ @sample.a_method.should_not eq 'hello'
24
+ end
25
+
26
+ it "should provision a method using a class name" do
27
+ class ThisClass;
28
+ def provision!(sender)
29
+ false
30
+ end
31
+ end
32
+
33
+ @meta.provision :a_method, :with => ThisClass
34
+
35
+ @sample.a_method.should_not eq 'hello'
36
+ end
37
+
38
+ it "should provision a method using a class name with class method provision!" do
39
+ class ThisClass;
40
+ def self.provision!(sender)
41
+ false
42
+ end
43
+ end
44
+
45
+ @meta.provision :a_method, :with => ThisClass
46
+
47
+ @sample.a_method.should_not eq 'hello'
48
+ end
49
+
50
+ it "should provision a method using an instance of a class" do
51
+ class ThisClass; end
52
+ @instance = ThisClass.new
53
+ @instance.stub(:provision!).and_return false
54
+ @instance.should_receive(:provision!)
55
+
56
+ @meta.provision :a_method, :with => @instance
57
+
58
+ @sample.a_method.should_not eq 'hello'
59
+ end
60
+
61
+ it "should provision a method using an instance of a class (from a proc)" do
62
+ class ThisClass; end
63
+ ThisClass.any_instance.stub(:provision!).and_return false
64
+ ThisClass.any_instance.should_receive(:provision!)
65
+
66
+ @meta.provision :a_method, :with => lambda{ ThisClass.new }
67
+
68
+ @sample.a_method.should_not eq 'hello'
69
+ end
70
+
71
+ it "should provision a method using a proc" do
72
+ @meta.provision :a_method, :with => lambda{ false }
73
+
74
+ @sample.a_method.should_not eq 'hello'
75
+ end
76
+
77
+ it "should takea proc with arguments" do
78
+ @meta.provision :a_method, :with => lambda{ |sender, p| sender === @sample && p == 'p' }
79
+
80
+ @sample.a_method('p').should eq 'hello'
81
+ end
82
+
83
+ it "should take an array of methods to provision" do
84
+ @sample.stub(:b_method).and_return('hello')
85
+ @meta.provision :a_method, :b_method, :with => lambda{ false }
86
+
87
+ @sample.a_method.should_not eq 'hello'
88
+ @sample.b_method.should_not eq 'hello'
89
+ end
90
+
91
+ it "should take a block as an action when provision fails" do
92
+ @meta.provision :a_method, :with => lambda{ false } do
93
+ 'hi there'
94
+ end
95
+
96
+ @sample.a_method.should eq 'hi there'
97
+ end
98
+
99
+ end
@@ -0,0 +1 @@
1
+ require 'provision'
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: provision
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chen Fisher
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Lets one hook a provision for a method
31
+ email:
32
+ - chen.fisher@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - .rspec
39
+ - CHANGELOG.md
40
+ - Gemfile
41
+ - LICENSE.txt
42
+ - README.md
43
+ - Rakefile
44
+ - lib/provision.rb
45
+ - lib/provision/version.rb
46
+ - provision.gemspec
47
+ - spec/provision/sample.rb
48
+ - spec/provision_spec.rb
49
+ - spec/spec_helper.rb
50
+ homepage: https://github.com/chenfisher/provision
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 1.8.24
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: When a method is provisioned, any call to that method is passed through a
74
+ provision filter that can stop the method execution and perform some actions
75
+ test_files:
76
+ - spec/provision/sample.rb
77
+ - spec/provision_spec.rb
78
+ - spec/spec_helper.rb