amountable 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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