subly 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ bin/*
6
+ .idea/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create ruby-1.8.7@subly
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in subly.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 SmashTank Apps, LLC
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,35 @@
1
+ = Subly
2
+
3
+ This gem provides the ability to add subscriptions to models that is controlled from an external app
4
+
5
+ == Usage
6
+ subly accepts a single optional parameter of :is_methods
7
+ class Item < ActiveRecord::Base
8
+ subly :is_methods => [:premium, :standard]
9
+ end
10
+
11
+ == Migration
12
+ See the last todo, this needs to me a generator/rake task but I am tired and want to goto sleep
13
+ create_table :subly_models do |t|
14
+ t.string :subscriber_type
15
+ t.integer :subscriber_id
16
+ t.string :name
17
+ t.string :value
18
+ t.datetime :starts_at
19
+ t.datetime :ends_at
20
+ end
21
+ add_index :subly_models, [:subscriber_type,:subscriber_id], :name => 'subscriber_idx'
22
+ add_index :subly_models, :starts_at, :name => 'starts_idx'
23
+ add_index :subly_models, :ends_at, :name => 'ends_idx'
24
+
25
+ == Todo
26
+ * maybe add a controller
27
+ * do something with the value field, I think it useful but can't think of a use case yet.
28
+ * make the doco usefull
29
+ * make a generator for rails 2 and 3
30
+
31
+ == Copyright
32
+
33
+ Copyright (c) 2011 SmashTank Apps, LLC. See LICENSE.txt for
34
+ further details.
35
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,57 @@
1
+ require "subly/version"
2
+ require "subly/model"
3
+
4
+ module Subly
5
+ def subly(args = {})
6
+ self.has_many :sublies, :as => :subscriber, :class_name => 'Subly::Model'
7
+ self.accepts_nested_attributes_for :sublies, :allow_destroy => true, :reject_if => :all_blank
8
+
9
+ #we don't want to use method missing for all "is" methods
10
+ if is_methods = args.delete(:is_methods)
11
+ is_methods.collect(&:to_s).each do |is_name|
12
+ if self.instance_methods.include?(is_name)
13
+ warn("Subly: Method is_#{is_name}? is already available to #{self.class.to_s}")
14
+ else
15
+ self.class_eval <<-EOV
16
+ def is_#{is_name}?
17
+ self.has_active_subscription?('#{is_name}')
18
+ end
19
+ EOV
20
+ end
21
+ end
22
+ end
23
+
24
+ extend ClassMethods
25
+ include InstanceMethods
26
+ end
27
+
28
+ module ClassMethods
29
+ def with_subscription(name)
30
+ scoped(:include => :sublies, :conditions => {:subly_models => {:name => name}})
31
+ end
32
+
33
+ def with_active_subscription(name)
34
+ now = Time.now
35
+ with_subscription(name).scoped(:joins => :sublies, :conditions => ['subly_models.starts_at <= ? AND (ends_at IS NULL or ends_at > ?)', now, now])
36
+ end
37
+ end
38
+
39
+ module InstanceMethods
40
+ def add_subscription(name, args = {})
41
+ value = args[:value] || nil
42
+ start_date = args[:start_date] || Time.now
43
+ end_date = args[:end_date] || nil
44
+ self.sublies.create(:name => name, :value => value, :starts_at => start_date, :ends_at => end_date)
45
+ end
46
+
47
+ def has_subscription?(name)
48
+ self.sublies.by_name(name).count > 0
49
+ end
50
+
51
+ def has_active_subscription?(name)
52
+ self.sublies.active.by_name(name).count > 0
53
+ end
54
+ end
55
+ end
56
+
57
+ ActiveRecord::Base.send :extend, Subly
@@ -0,0 +1,37 @@
1
+ module Subly
2
+ class Model < ActiveRecord::Base
3
+ set_table_name 'subly_models'
4
+
5
+ belongs_to :subscriber, :polymorphic => true
6
+
7
+ validates_presence_of :subscriber_type
8
+ validates_presence_of :subscriber_id, :unless => Proc.new { |subly| subly.subscriber_type.nil? }
9
+ validate :ends_after_starts
10
+
11
+ def self.active
12
+ now = Time.now
13
+ scoped(:conditions => ['starts_at <= ? AND (ends_at > ? OR ends_at IS NULL)', now, now])
14
+ end
15
+
16
+ def self.expired
17
+ now = Time.now
18
+ scoped(:conditions => ['starts_at <= ? AND ends_at <= ?', now, now])
19
+ end
20
+
21
+ def self.for_subscriber(sub)
22
+ raise ArgumentError('wrong number of arguments (0 for 1)') if sub.blank?
23
+ scoped(:conditions => ['subscriber_type = ? AND subscriber_id = ?',sub.class.to_s, sub.id])
24
+ end
25
+
26
+ def self.by_name(name)
27
+ scoped(:conditions => {:name => name})
28
+ end
29
+
30
+ private
31
+ def ends_after_starts
32
+ unless ends_at.nil? || (ends_at > starts_at)
33
+ raise "ends_at must be after starts_at"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module Subly
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,43 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'active_record'
4
+ require 'rspec'
5
+ require 'subly'
6
+ require 'sqlite3'
7
+
8
+ # Requires supporting files with custom matchers and macros, etc,
9
+ # in ./support/ and its subdirectories.
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
+
12
+ #ActiveRecord::Schema.verbose = false
13
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
14
+
15
+ ActiveRecord::Base.configurations = true
16
+ ActiveRecord::Schema.define(:version => 1) do
17
+ create_table :items do |t|
18
+ t.datetime :created_at
19
+ t.datetime :updated_at
20
+ t.string :name
21
+ t.string :description
22
+ end
23
+
24
+ create_table :things do |t|
25
+ t.datetime :created_at
26
+ t.datetime :updated_at
27
+ t.string :name
28
+ t.string :description
29
+ end
30
+
31
+ create_table :subly_models do |t|
32
+ t.datetime :archived_at
33
+ t.string :subscriber_type
34
+ t.integer :subscriber_id
35
+ t.string :name
36
+ t.string :value
37
+ t.datetime :starts_at
38
+ t.datetime :ends_at
39
+ end
40
+ add_index :subly_models, [:subscriber_type,:subscriber_id], :name => 'subscriber_idx'
41
+ add_index :subly_models, :starts_at, :name => 'starts_idx'
42
+ add_index :subly_models, :ends_at, :name => 'ends_idx'
43
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class Item < ActiveRecord::Base
4
+ subly
5
+ end
6
+
7
+ class Thing < ActiveRecord::Base
8
+ subly
9
+ end
10
+
11
+ describe Subly::Model do
12
+ it "should not create a subscription without a subscriber_id" do
13
+ lambda{Subly::Model.create!(:name => 'Foo', :subscriber_type => 'Boo')}.should raise_error
14
+ end
15
+
16
+ it "should not create a subscription without a subscriber" do
17
+ lambda{Subly::Model.create!(:name => 'Foo', :subscriber_id => 3)}.should raise_error
18
+ end
19
+
20
+ it "subscription should not be created when ends before starts" do
21
+ lambda{Subly::Model.create!(:name => 'Foo', :subscriber_type => 'Foo', :subscriber_id => 1, :starts_at => Time.now + 1.minute, :ends_at => Time.now - 1.minute)}.should raise_error
22
+ end
23
+ end
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class Item < ActiveRecord::Base
4
+ subly :is_methods => [:subby]
5
+ end
6
+
7
+ class Thing < ActiveRecord::Base
8
+ subly
9
+ end
10
+
11
+ describe Subly do
12
+ it "should add a subscription" do
13
+ thing_one = Thing.create(:name => 'Thing One', :description => 'foo')
14
+ thing_one.add_subscription('sub name','sub value').should be_true
15
+ thing_one.reload
16
+ thing_one.sublies.count.should == 1
17
+ end
18
+
19
+ it "subscription should default to active" do
20
+ thing_one = Thing.create(:name => 'Thing One', :description => 'foo')
21
+ thing_one.add_subscription('sub name').should be_true
22
+ thing_one.reload
23
+ thing_one.has_active_subscription?('sub name').should be_true
24
+ end
25
+
26
+ it "has_subscription should return true even for expired subscription" do
27
+ thing_one = Thing.create(:name => 'Thing One', :description => 'foo')
28
+ thing_one.add_subscription('sub name', :start_date => Time.now - 1.day, :end_date => Time.now - 2.hours).should be_true
29
+ thing_one.reload
30
+ thing_one.has_subscription?('sub name').should be_true
31
+ end
32
+
33
+
34
+ it "should find models with active subscription" do
35
+ Thing.delete_all
36
+ thing_one = Thing.create(:name => 'Thing One', :description => 'foo')
37
+ thing_one.add_subscription('sub name').should be_true
38
+ Thing.with_active_subscription('sub name').should == [thing_one]
39
+ end
40
+
41
+ it "should find models with even expired subscriptions" do
42
+ Thing.delete_all
43
+ thing_one = Thing.create(:name => 'Thing One', :description => 'foo')
44
+ thing_one.add_subscription('sub name', :start_date => Time.now - 1.day, :end_date => Time.now - 2.hours).should be_true
45
+ Thing.with_subscription('sub name').should == [thing_one]
46
+ thing_one.destroy
47
+ end
48
+
49
+ it "should define methods for is" do
50
+ Item.instance_method(:is_subby?).should be_true
51
+ end
52
+
53
+ it "is method should be false if it does not have an active sub" do
54
+ Item.new.is_subby?.should be_false
55
+ end
56
+
57
+ it "is method should be true if it has an active sub" do
58
+ item = Item.create(:name => 'foo')
59
+ item.add_subscription('subby')
60
+ item.is_subby?.should be_true
61
+ end
62
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "subly/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "subly"
7
+ s.version = Subly::VERSION
8
+ s.authors = ['SmashTank Apps, LLC','Eric Harrison']
9
+ s.email = ['dev@smashtankapps.com']
10
+ s.homepage = "http://github.com/smashtank/subly"
11
+ s.summary = %q{Add subscriptions to a model that are controlled externally}
12
+ s.description = %q{This was purpose built to extend models with subscriptions that were controlled via SalesForce}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.require_paths = ["lib"]
17
+
18
+ s.required_rubygems_version = ">= 1.3.6"
19
+ s.add_development_dependency "activerecord", "~> 2.3.12"
20
+ s.add_development_dependency "rspec"
21
+ s.add_development_dependency "sqlite3"
22
+
23
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: subly
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - SmashTank Apps, LLC
9
+ - Eric Harrison
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-12-02 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ requirement: &2153605660 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 2.3.12
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2153605660
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &2153605280 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2153605280
37
+ - !ruby/object:Gem::Dependency
38
+ name: sqlite3
39
+ requirement: &2153604820 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *2153604820
48
+ description: This was purpose built to extend models with subscriptions that were
49
+ controlled via SalesForce
50
+ email:
51
+ - dev@smashtankapps.com
52
+ executables: []
53
+ extensions: []
54
+ extra_rdoc_files: []
55
+ files:
56
+ - .gitignore
57
+ - .rvmrc
58
+ - Gemfile
59
+ - LICENSE.txt
60
+ - README.rdoc
61
+ - Rakefile
62
+ - lib/subly.rb
63
+ - lib/subly/model.rb
64
+ - lib/subly/version.rb
65
+ - spec/spec_helper.rb
66
+ - spec/subly_model_spec.rb
67
+ - spec/subly_spec.rb
68
+ - subly.gemspec
69
+ homepage: http://github.com/smashtank/subly
70
+ licenses: []
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: 1.3.6
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 1.8.10
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Add subscriptions to a model that are controlled externally
93
+ test_files:
94
+ - spec/spec_helper.rb
95
+ - spec/subly_model_spec.rb
96
+ - spec/subly_spec.rb