amountable 0.0.2

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eaab8de5d539d970c93a407222cddfbdcb0b3cef
4
+ data.tar.gz: ef1f96155420b3adddbfab6ce97fbaffd7bafe8f
5
+ SHA512:
6
+ metadata.gz: 67aa3b1d6d456f2c3c3e2005ef6a009be518be79492cc2edbdfae92a2b011661e8ae51d7cd959d5794d5044e9ec80ad8132245acceb1832ce910f5607ff280d3
7
+ data.tar.gz: 38ffecf5763a50f826ca60c4304cdf721e91814a6bdb08aacddf5fdb2da21ddffb965243c07cd396d16a2d47c862d218fd06efecc0789a5b6467c756f5de34a4
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - "2.2.0"
4
+ script:
5
+ - bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,157 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ amountable (0.0.1)
5
+ activerecord-import (= 0.10.0)
6
+ monetize
7
+ money-rails
8
+ rails (~> 4.2)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ actionmailer (4.2.5)
14
+ actionpack (= 4.2.5)
15
+ actionview (= 4.2.5)
16
+ activejob (= 4.2.5)
17
+ mail (~> 2.5, >= 2.5.4)
18
+ rails-dom-testing (~> 1.0, >= 1.0.5)
19
+ actionpack (4.2.5)
20
+ actionview (= 4.2.5)
21
+ activesupport (= 4.2.5)
22
+ rack (~> 1.6)
23
+ rack-test (~> 0.6.2)
24
+ rails-dom-testing (~> 1.0, >= 1.0.5)
25
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
26
+ actionview (4.2.5)
27
+ activesupport (= 4.2.5)
28
+ builder (~> 3.1)
29
+ erubis (~> 2.7.0)
30
+ rails-dom-testing (~> 1.0, >= 1.0.5)
31
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
32
+ activejob (4.2.5)
33
+ activesupport (= 4.2.5)
34
+ globalid (>= 0.3.0)
35
+ activemodel (4.2.5)
36
+ activesupport (= 4.2.5)
37
+ builder (~> 3.1)
38
+ activerecord (4.2.5)
39
+ activemodel (= 4.2.5)
40
+ activesupport (= 4.2.5)
41
+ arel (~> 6.0)
42
+ activerecord-import (0.10.0)
43
+ activerecord (>= 3.0)
44
+ activesupport (4.2.5)
45
+ i18n (~> 0.7)
46
+ json (~> 1.7, >= 1.7.7)
47
+ minitest (~> 5.1)
48
+ thread_safe (~> 0.3, >= 0.3.4)
49
+ tzinfo (~> 1.1)
50
+ arel (6.0.3)
51
+ builder (3.2.2)
52
+ concurrent-ruby (1.0.0)
53
+ database_cleaner (1.5.1)
54
+ db-query-matchers (0.3.0)
55
+ diff-lcs (1.2.5)
56
+ erubis (2.7.0)
57
+ globalid (0.3.6)
58
+ activesupport (>= 4.1.0)
59
+ i18n (0.7.0)
60
+ json (1.8.3)
61
+ loofah (2.0.3)
62
+ nokogiri (>= 1.5.9)
63
+ mail (2.6.3)
64
+ mime-types (>= 1.16, < 3)
65
+ mime-types (2.99)
66
+ mini_portile (0.6.2)
67
+ minitest (5.8.3)
68
+ monetize (1.1.0)
69
+ money (~> 6.5.0)
70
+ money (6.5.1)
71
+ i18n (>= 0.6.4, <= 0.7.0)
72
+ money-rails (1.4.1)
73
+ activesupport (>= 3.0)
74
+ monetize (~> 1.1.0)
75
+ money (~> 6.5.0)
76
+ railties (>= 3.0)
77
+ mysql2 (0.3.15)
78
+ nokogiri (1.6.6.2)
79
+ mini_portile (~> 0.6.0)
80
+ pg (0.18.1)
81
+ rack (1.6.4)
82
+ rack-test (0.6.3)
83
+ rack (>= 1.0)
84
+ rails (4.2.5)
85
+ actionmailer (= 4.2.5)
86
+ actionpack (= 4.2.5)
87
+ actionview (= 4.2.5)
88
+ activejob (= 4.2.5)
89
+ activemodel (= 4.2.5)
90
+ activerecord (= 4.2.5)
91
+ activesupport (= 4.2.5)
92
+ bundler (>= 1.3.0, < 2.0)
93
+ railties (= 4.2.5)
94
+ sprockets-rails
95
+ rails-deprecated_sanitizer (1.0.3)
96
+ activesupport (>= 4.2.0.alpha)
97
+ rails-dom-testing (1.0.7)
98
+ activesupport (>= 4.2.0.beta, < 5.0)
99
+ nokogiri (~> 1.6.0)
100
+ rails-deprecated_sanitizer (>= 1.0.1)
101
+ rails-html-sanitizer (1.0.2)
102
+ loofah (~> 2.0)
103
+ railties (4.2.5)
104
+ actionpack (= 4.2.5)
105
+ activesupport (= 4.2.5)
106
+ rake (>= 0.8.7)
107
+ thor (>= 0.18.1, < 2.0)
108
+ rake (10.4.2)
109
+ rspec (3.4.0)
110
+ rspec-core (~> 3.4.0)
111
+ rspec-expectations (~> 3.4.0)
112
+ rspec-mocks (~> 3.4.0)
113
+ rspec-core (3.4.1)
114
+ rspec-support (~> 3.4.0)
115
+ rspec-expectations (3.4.0)
116
+ diff-lcs (>= 1.2.0, < 2.0)
117
+ rspec-support (~> 3.4.0)
118
+ rspec-mocks (3.4.0)
119
+ diff-lcs (>= 1.2.0, < 2.0)
120
+ rspec-support (~> 3.4.0)
121
+ rspec-rails (3.4.0)
122
+ actionpack (>= 3.0, < 4.3)
123
+ activesupport (>= 3.0, < 4.3)
124
+ railties (>= 3.0, < 4.3)
125
+ rspec-core (~> 3.4.0)
126
+ rspec-expectations (~> 3.4.0)
127
+ rspec-mocks (~> 3.4.0)
128
+ rspec-support (~> 3.4.0)
129
+ rspec-support (3.4.1)
130
+ sprockets (3.5.2)
131
+ concurrent-ruby (~> 1.0)
132
+ rack (> 1, < 3)
133
+ sprockets-rails (2.3.3)
134
+ actionpack (>= 3.0)
135
+ activesupport (>= 3.0)
136
+ sprockets (>= 2.8, < 4.0)
137
+ sqlite3 (1.3.11)
138
+ thor (0.19.1)
139
+ thread_safe (0.3.5)
140
+ tzinfo (1.2.2)
141
+ thread_safe (~> 0.1)
142
+
143
+ PLATFORMS
144
+ ruby
145
+
146
+ DEPENDENCIES
147
+ amountable!
148
+ database_cleaner
149
+ db-query-matchers
150
+ mysql2
151
+ pg
152
+ rspec
153
+ rspec-rails
154
+ sqlite3
155
+
156
+ BUNDLED WITH
157
+ 1.10.6
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright © 2015, Instacart
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,75 @@
1
+ # Amountable
2
+
3
+ [![Build Status](https://travis-ci.org/instacart/amountable.svg?branch=master)](https://travis-ci.org/instacart/amountable)
4
+
5
+ This gem helps you integrate Money fields into your ActiveRecord models without having to add new columns each time.
6
+
7
+ It also helps manage and sum various components of your models to keep amount definitions consistent across your application.
8
+
9
+ ## Installation
10
+
11
+ Add
12
+
13
+ ```ruby
14
+ gem 'amountable', github: 'instacart/amountable'
15
+ ```
16
+
17
+ to your `Gemfile`. Then run
18
+
19
+ ```shell
20
+ bundle
21
+ ```
22
+
23
+ and
24
+
25
+ ```shell
26
+ rake amountable:install:migrations
27
+ ```
28
+
29
+ and finally
30
+
31
+ ```shell
32
+ rake db:migrate
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ Setup your model
38
+
39
+ ```ruby
40
+ class Order < ActiveRecord::Base
41
+ include Amountable
42
+ amount :subtotal, sets: [:total]
43
+ amount :delivery_fee, sets: [:total, :fees]
44
+ amount :bags_fee, sets: [:total, :fees]
45
+ amount :sales_tax, sets: [:total, :taxes]
46
+ amount :local_tax, sets: [:total, :taxes]
47
+ end
48
+ ```
49
+
50
+ then create it
51
+
52
+ ```ruby
53
+ order = Order.create(
54
+ subtotal: Money.new(123),
55
+ delivery_fee: Money.new(100),
56
+ bags_fee: Money.new(10),
57
+ sales_tax: Money.new(56)
58
+ )
59
+ order.subtotal
60
+ # => #<Money fractional:123 currency:USD>
61
+ order.total
62
+ # => #<Money fractional:289 currency:USD>
63
+ order.fees
64
+ # => #<Money fractional:110 currency:USD>
65
+ order.taxes
66
+ # => #<Money fractional:56 currency:USD>
67
+ ```
68
+
69
+ ## Implementation
70
+
71
+ When you run the migration, an `amounts` table will be created with a polymorphic relationship to an `amountable`, which in the above example would be your orders.
72
+
73
+ When the an order is created with some amounts, the associated `Amount` objects are persisted.
74
+
75
+ `Amount` objects are persisted in bulk, so there are no N + 1 queries. If an amount is zero, no `Amount` model is created.
@@ -0,0 +1,34 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'amountable/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'amountable'
7
+ gem.version = Amountable::VERSION
8
+ gem.authors = ['Emmanuel Turlay']
9
+ gem.email = %w(emmanuel@instacart.com)
10
+ gem.description = %q{With Amountable, you can easily attach, organize and sum Ruby money fields to your models without migrating.}
11
+ gem.summary = 'Easy Money fields for your Rails models.'
12
+ gem.homepage = 'https://github.com/instacart/amountable'
13
+ # gem.license = 'MIT'
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.test_files = gem.files.grep(%r{^spec/})
17
+ gem.require_paths = ['lib']
18
+ gem.required_ruby_version = '>= 2.1.1'
19
+
20
+ gem.add_dependency 'rails', '~> 4.2'
21
+ #gem.add_dependency 'activerecord', ['>= 4.2', '< 5']
22
+ gem.add_dependency 'activerecord-import', '0.10.0'
23
+ gem.add_dependency 'money-rails'
24
+ gem.add_dependency 'monetize'
25
+
26
+ gem.add_development_dependency 'sqlite3'
27
+ gem.add_development_dependency 'mysql2'
28
+ gem.add_development_dependency 'pg'
29
+
30
+ gem.add_development_dependency 'rspec-rails'
31
+ gem.add_development_dependency 'rspec'
32
+ gem.add_development_dependency 'database_cleaner'
33
+ gem.add_development_dependency 'db-query-matchers'
34
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ class CreateAmounts < ActiveRecord::Migration
4
+ def change
5
+ create_table :amounts do |t|
6
+ t.integer :amountable_id, null: false
7
+ t.string :amountable_type, null: false
8
+ t.string :name, null: false
9
+ t.timestamps
10
+ end
11
+
12
+ add_monetize :amounts, :value
13
+
14
+ add_index :amounts, [:amountable_id, :amountable_type]
15
+
16
+ ActiveRecord::Base.connection.execute("CLUSTER amounts USING index_amounts_on_amountable_id_and_amountable_type") if is_pg?
17
+ end
18
+
19
+ def is_pg?
20
+ ActiveRecord::Base.connection.instance_values["config"][:adapter].include?('postgresql')
21
+ end
22
+ end
@@ -0,0 +1,122 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ module Amountable
4
+ extend ActiveSupport::Autoload
5
+ autoload :Amount
6
+ autoload :VERSION
7
+
8
+ class InvalidAmountName < StandardError; end
9
+
10
+ def self.included(base)
11
+
12
+ base.extend Amountable::ClassMethods
13
+
14
+ base.class_eval do
15
+ has_many :amounts, as: :amountable, dependent: :destroy, autosave: false
16
+ validate :validate_amount_names
17
+ class_attribute :amount_names
18
+ class_attribute :amount_sets
19
+ self.amount_sets = Hash.new { |h, k| h[k] = Set.new }
20
+ self.amount_names = Set.new
21
+
22
+ def all_amounts
23
+ @all_amounts ||= amounts.to_set
24
+ end
25
+
26
+ def find_amount(name)
27
+ (@amounts_by_name ||= {})[name.to_sym] ||= all_amounts.find { |am| am.name == name.to_s }
28
+ end
29
+
30
+ def find_amounts(names)
31
+ all_amounts.select { |am| names.include?(am.name.to_sym) }
32
+ end
33
+
34
+ def validate_amount_names
35
+ amounts.each do |amount|
36
+ errors.add(:amounts, "#{amount.name} is not an allowed amount name.") unless self.class.allowed_amount_name?(amount.name)
37
+ end
38
+ end
39
+
40
+ def serializable_hash(opts = nil)
41
+ opts ||= {}
42
+ super(opts).tap do |base|
43
+ unless opts[:except].to_a.include?(:amounts)
44
+ amounts_json = (self.class.amount_names + self.class.amount_sets.keys).inject({}) do |mem, name|
45
+ mem.merge!(name.to_s => send(name).to_f) unless opts[:except].to_a.include?(name.to_sym)
46
+ mem
47
+ end
48
+ base.merge!(amounts_json)
49
+ end
50
+ end
51
+ end
52
+
53
+ def save(args = {})
54
+ ActiveRecord::Base.transaction do
55
+ save_amounts if super(args)
56
+ end
57
+ end
58
+
59
+ def save!(args = {})
60
+ ActiveRecord::Base.transaction do
61
+ save_amounts! if super(args)
62
+ end
63
+ end
64
+
65
+ def save_amounts(bang: false)
66
+ amounts_to_insert = []
67
+ amounts.each do |amount|
68
+ if amount.new_record?
69
+ amount.amountable_id = self.id
70
+ amounts_to_insert << amount
71
+ else
72
+ bang ? amount.save! : amount.save
73
+ end
74
+ end
75
+ Amount.import(amounts_to_insert, timestamps: true, validate: false)
76
+ amounts_to_insert.each do |amount|
77
+ amount.instance_variable_set(:@new_record, false)
78
+ end
79
+ true
80
+ end
81
+
82
+ def save_amounts!; save_amounts(bang: true); end
83
+
84
+ end
85
+ end
86
+
87
+ module ClassMethods
88
+
89
+ def amount_set(set_name, component)
90
+ self.amount_sets[set_name.to_sym] << component.to_sym
91
+
92
+ define_method set_name do
93
+ find_amounts(self.amount_sets[set_name.to_sym]).sum(Money.zero, &:value)
94
+ end
95
+ end
96
+
97
+ def amount(name, options = {})
98
+ (self.amount_names ||= Set.new) << name
99
+
100
+ define_method name do
101
+ (find_amount(name) || NilAmount.new).value
102
+ end
103
+
104
+ define_method "#{name}=" do |value|
105
+ return Money.zero if value.zero?
106
+ amount = find_amount(name) || amounts.build(name: name)
107
+ amount.value = value.to_money
108
+ all_amounts << amount if amount.new_record?
109
+ (@amounts_by_name ||= {})[name.to_sym] = amount
110
+ end
111
+
112
+ Array(options[:summable] || options[:summables] || options[:set] || options[:sets] || options[:amount_set] || options[:amount_sets]).each do |set|
113
+ amount_set(set, name)
114
+ end
115
+ end
116
+
117
+ def allowed_amount_name?(name)
118
+ self.amount_names.include?(name.to_sym)
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ class Amount < ActiveRecord::Base
4
+
5
+ belongs_to :amountable, polymorphic: true
6
+
7
+ monetize :value_cents
8
+
9
+ validates :name, presence: true
10
+ validates :name, uniqueness: {scope: [:amountable_id, :amountable_type]}
11
+
12
+ module Operations
13
+
14
+ def +(other_value)
15
+ value + other_value.to_money
16
+ end
17
+
18
+ def -(other_value)
19
+ value - other_value.to_money
20
+ end
21
+
22
+ def *(multiplier)
23
+ value * multiplier
24
+ end
25
+
26
+ def /(divisor)
27
+ value / divisor
28
+ end
29
+
30
+ def to_money
31
+ value
32
+ end
33
+
34
+ end
35
+ include Operations
36
+ end
37
+
38
+ class NilAmount
39
+ include Amount::Operations
40
+ def value; Money.zero; end
41
+ def amountable; nil; end
42
+ end
@@ -0,0 +1,5 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ module Amountable
4
+ VERSION = '0.0.2'
5
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Amount do
6
+
7
+ it 'should validate name presence' do
8
+ Amount.new.tap do |amount|
9
+ expect(amount.valid?).to be false
10
+ expect(amount.errors[:name]).not_to be nil
11
+ end
12
+ end
13
+
14
+ it 'should validate name uniqueness' do
15
+ Amount.new(name: 'test', amountable_id: 1, amountable_type: 'Amountable').tap do |amount|
16
+ expect(amount.valid?).to be true
17
+ amount.save
18
+ Amount.new(name: 'test', amountable_id: 2, amountable_type: 'Amountable').tap do |other_amount|
19
+ expect(other_amount.valid?).to be true
20
+ other_amount.amountable_id = amount.amountable_id
21
+ expect(other_amount.valid?).to be false
22
+ expect(amount.errors[:name]).not_to be nil
23
+ end
24
+ end
25
+ end
26
+
27
+ it 'should have operations' do
28
+ expect(Amount.new(value: Money.new(1)) + Amount.new(value: Money.new(2))).to eq(Money.new(3))
29
+ expect(Amount.new(value: Money.new(1)) + 0.02).to eq(Money.new(3))
30
+ expect(Amount.new(value: Money.new(2)) - Amount.new(value: Money.new(1))).to eq(Money.new(1))
31
+ expect(Amount.new(value: Money.new(2)) - 0.01).to eq(Money.new(1))
32
+ expect(Amount.new(value: Money.new(2)) * 3).to eq(Money.new(6))
33
+ expect(Amount.new(value: Money.new(6)) / 3).to eq(Money.new(2))
34
+ expect(Amount.new(value: Money.new(2)).to_money).to eq(Money.new(2))
35
+ end
36
+
37
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Amountable do
6
+
7
+ it 'should' do
8
+ order = Order.new
9
+ expect {
10
+ order.save
11
+ }.not_to change {
12
+ Amount.count
13
+ }
14
+ %i(sub_total taxes total).each do |name|
15
+ expect(order.send(name)).to eq(Money.zero)
16
+ end
17
+ order.sub_total = Money.new(100)
18
+ expect(order.sub_total).to eq(Money.new(100))
19
+ expect(order.total).to eq(Money.new(100))
20
+ expect(order.all_amounts.size).to eq(1)
21
+ order.all_amounts.first.tap do |amount|
22
+ expect(amount.name).to eq('sub_total')
23
+ expect(amount.value).to eq(Money.new(100))
24
+ expect(amount.new_record?).to be true
25
+ expect {
26
+ order.save
27
+ }.to change {
28
+ Amount.count
29
+ }.by(1)
30
+ expect(amount.persisted?).to be true
31
+ end
32
+ expect{
33
+ expect(order.update_attributes(sub_total: Money.new(200)))
34
+ }.not_to change {
35
+ Amount.count
36
+ }
37
+ end
38
+
39
+ it 'should insert amounts in bulk' do
40
+ order = Order.create
41
+ expect {
42
+ order.update(sub_total: Money.new(100), taxes: Money.new(200))
43
+ }.to make_database_queries(count: 1, manipulative: true)
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ require 'spec_helper'
4
+
5
+ describe NilAmount do
6
+
7
+ it 'should return 0' do
8
+ expect(NilAmount.new.value).to eq(Money.zero)
9
+ end
10
+
11
+ it 'should have nil amountable' do
12
+ expect(NilAmount.new.amountable).to be nil
13
+ end
14
+
15
+ it 'should have operations' do
16
+ expect(NilAmount.new + Amount.new(value: Money.new(2))).to eq(Money.new(2))
17
+ expect(NilAmount.new + 0.02).to eq(Money.new(2))
18
+ expect(NilAmount.new - Amount.new(value: Money.new(1))).to eq(Money.new(-1))
19
+ expect(NilAmount.new - 0.01).to eq(Money.new(-1))
20
+ expect(NilAmount.new * 3).to eq(Money.zero)
21
+ expect(NilAmount.new / 3).to eq(Money.zero)
22
+ expect(NilAmount.new.to_money).to eq(Money.zero)
23
+ end
24
+
25
+ end
@@ -0,0 +1,10 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ class Order < ActiveRecord::Base
4
+
5
+ include Amountable
6
+
7
+ amount :sub_total, sets: [:total]
8
+ amount :taxes, sets: [:total]
9
+
10
+ end
@@ -0,0 +1,7 @@
1
+ postgresql:
2
+ adapter: postgresql
3
+ hostname: localhost
4
+ username:
5
+ password:
6
+ database: amountable_test
7
+ encoding: utf8
@@ -0,0 +1,19 @@
1
+ sqlite3:
2
+ adapter: sqlite3
3
+ database: ':memory:'
4
+
5
+ mysql:
6
+ adapter: mysql2
7
+ host: localhost
8
+ username: root
9
+ password:
10
+ database: amountable
11
+ charset: utf8
12
+
13
+ postgresql:
14
+ adapter: postgresql
15
+ hostname: localhost
16
+ username: postgres
17
+ password:
18
+ database: amountable
19
+ encoding: utf8
@@ -0,0 +1,21 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ ActiveRecord::Schema.define version: 1 do
4
+
5
+ create_table "amounts", force: :cascade do |t|
6
+ t.integer "amountable_id", null: false
7
+ t.string "amountable_type", null: false
8
+ t.datetime "created_at"
9
+ t.string "name", null: false
10
+ t.datetime "updated_at"
11
+ t.integer "value_cents", default: 0, null: false
12
+ t.string "value_currency", default: "USD", null: false
13
+ end
14
+
15
+ add_index "amounts", ["amountable_id", "amountable_type"], name: "index_amounts_on_amountable_id_and_amountable_type", using: :btree
16
+
17
+ create_table "orders" do |t|
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ ENV['RAILS_ENV'] = 'test'
4
+ require 'rails'
5
+ require 'money-rails'
6
+ require 'active_record'
7
+ require 'activerecord-import'
8
+ require 'amountable'
9
+ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
10
+ MoneyRails::Hooks.init
11
+ require 'amountable/amount'
12
+ require 'database_cleaner'
13
+ require 'db-query-matchers'
14
+
15
+ RSpec.configure do |config|
16
+
17
+ config.before(:suite) do
18
+ DatabaseCleaner.strategy = :transaction
19
+ DatabaseCleaner.clean_with(:truncation)
20
+ end
21
+
22
+ config.around(:each) do |example|
23
+ DatabaseCleaner.cleaning do
24
+ example.run
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright 2015, Instacart
2
+
3
+ db_name = ENV['DB'] || 'postgresql'
4
+ database_yml = File.expand_path('../../internal/config/database.yml', __FILE__)
5
+
6
+ if File.exist?(database_yml)
7
+
8
+ ActiveRecord::Migration.verbose = false
9
+ ActiveRecord::Base.default_timezone = :utc
10
+ ActiveRecord::Base.configurations = YAML.load_file(database_yml)
11
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), '../debug.log'))
12
+ ActiveRecord::Base.logger.level = ENV['TRAVIS'] ? ::Logger::ERROR : ::Logger::DEBUG
13
+ config = ActiveRecord::Base.configurations[db_name]
14
+
15
+ begin
16
+ ActiveRecord::Base.establish_connection(db_name.to_sym)
17
+ ActiveRecord::Base.connection
18
+ rescue
19
+ case db_name
20
+ when /mysql/
21
+ ActiveRecord::Base.establish_connection(config.merge('database' => nil))
22
+ ActiveRecord::Base.connection.create_database(config['database'], {charset: 'utf8', collation: 'utf8_unicode_ci'})
23
+ when 'postgresql'
24
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
25
+ ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => 'utf8'))
26
+ end
27
+
28
+ ActiveRecord::Base.establish_connection(config)
29
+ end
30
+
31
+ load(File.dirname(__FILE__) + '/../internal/db/schema.rb')
32
+ load(File.dirname(__FILE__) + '/../internal/app/models/order.rb')
33
+
34
+ else
35
+ fail "Please create #{database_yml} first to configure your database. Take a look at: #{database_yml}.sample"
36
+ end
metadata ADDED
@@ -0,0 +1,227 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amountable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Emmanuel Turlay
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord-import
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.10.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.10.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: money-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: monetize
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mysql2
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pg
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-rails
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: database_cleaner
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: db-query-matchers
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: With Amountable, you can easily attach, organize and sum Ruby money fields
168
+ to your models without migrating.
169
+ email:
170
+ - emmanuel@instacart.com
171
+ executables: []
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - ".rspec"
176
+ - ".travis.yml"
177
+ - Gemfile
178
+ - Gemfile.lock
179
+ - LICENSE
180
+ - README.md
181
+ - amountable.gemspec
182
+ - db/migrate/0_create_amounts.rb
183
+ - lib/amountable.rb
184
+ - lib/amountable/amount.rb
185
+ - lib/amountable/version.rb
186
+ - spec/amountable/amount_spec.rb
187
+ - spec/amountable/amountable_spec.rb
188
+ - spec/amountable/nil_amount_spec.rb
189
+ - spec/internal/app/models/order.rb
190
+ - spec/internal/config/database.yml
191
+ - spec/internal/config/database.yml.sample
192
+ - spec/internal/db/schema.rb
193
+ - spec/spec_helper.rb
194
+ - spec/support/database.rb
195
+ homepage: https://github.com/instacart/amountable
196
+ licenses: []
197
+ metadata: {}
198
+ post_install_message:
199
+ rdoc_options: []
200
+ require_paths:
201
+ - lib
202
+ required_ruby_version: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: 2.1.1
207
+ required_rubygems_version: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - ">="
210
+ - !ruby/object:Gem::Version
211
+ version: '0'
212
+ requirements: []
213
+ rubyforge_project:
214
+ rubygems_version: 2.4.5
215
+ signing_key:
216
+ specification_version: 4
217
+ summary: Easy Money fields for your Rails models.
218
+ test_files:
219
+ - spec/amountable/amount_spec.rb
220
+ - spec/amountable/amountable_spec.rb
221
+ - spec/amountable/nil_amount_spec.rb
222
+ - spec/internal/app/models/order.rb
223
+ - spec/internal/config/database.yml
224
+ - spec/internal/config/database.yml.sample
225
+ - spec/internal/db/schema.rb
226
+ - spec/spec_helper.rb
227
+ - spec/support/database.rb