Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit

  • Loading branch information...
commit f9c3df47625ee3e87bbd3eb67bc2d83cb04d6ffa 1 parent 3325caf
@kristianmandrup authored
Showing with 587 additions and 41 deletions.
  1. +9 −9 .gitignore
  2. +18 −11 Gemfile
  3. +59 −0 Gemfile.lock
  4. +23 −3 README.rdoc → README.md
  5. +2 −2 Rakefile
  6. +1 −0  lib/money-mongoid.rb
  7. +16 −0 lib/money/mongoid.rb
  8. +22 −0 lib/money/mongoid/2x/money.rb
  9. +38 −0 lib/money/mongoid/3x/money.rb
  10. +2 −0  lib/money/mongoid/core_ext.rb
  11. +5 −0 lib/money/mongoid/core_ext/array.rb
  12. +6 −0 lib/money/mongoid/core_ext/string.rb
  13. +29 −0 lib/money/mongoid/macros.rb
  14. +17 −0 lib/money/mongoid/monetizable.rb
  15. +35 −0 lib/money/mongoid/monetize.rb
  16. +24 −0 lib/money/orm/generic.rb
  17. +0 −7 spec/money-mongoid_spec.rb
  18. +14 −0 spec/money/mongoid/2x/money_spec.rb
  19. +6 −0 spec/money/mongoid/2x/product.rb
  20. +49 −0 spec/money/mongoid/3x/money_spec.rb
  21. +10 −0 spec/money/mongoid/3x/product.rb
  22. +12 −0 spec/money/mongoid/models/account.rb
  23. +15 −0 spec/money/mongoid/models/price.rb
  24. +87 −0 spec/money/mongoid/monetize_spec.rb
  25. +31 −0 spec/money/mongoid/spec_helper.rb
  26. +19 −0 spec/money/mongoid/support/mongoid.yml
  27. +37 −0 spec/money/mongoid/version_setup.rb
  28. +1 −9 spec/spec_helper.rb
View
18 .gitignore
@@ -28,22 +28,22 @@ pkg
#
# For MacOS:
#
-#.DS_Store
+.DS_Store
# For TextMate
-#*.tmproj
-#tmtags
+*.tmproj
+tmtags
# For emacs:
-#*~
-#\#*
-#.\#*
+*~
+\#*
+.\#*
# For vim:
-#*.swp
+*.swp
# For redcar:
-#.redcar
+.redcar
# For rubinius:
-#*.rbc
+*.rbc
View
29 Gemfile
@@ -1,14 +1,21 @@
-source "http://rubygems.org"
-# Add dependencies required to use your gem here.
-# Example:
-# gem "activesupport", ">= 2.3.5"
+source :rubygems
+
+gem 'money'
+
+gem 'mongoid', "~> 3.0.0.rc"
+gem 'moped'
+
+# gem 'mongoid', "~> 2.4"
+# gem 'bson'
-# Add dependencies to develop your gem here.
-# Include everything needed to run rake, tests, features, etc.
group :development do
- gem "rspec", "~> 2.8.0"
- gem "rdoc", "~> 3.12"
- gem "bundler", "~> 1.0.0"
- gem "jeweler", "~> 1.8.3"
- gem "rcov", ">= 0"
+ gem "rspec", "~> 2.10"
+ gem "rdoc", ">= 3.12"
+ gem "bundler", "~> 1.1.0"
+ gem "jeweler", ">= 1.8.3"
+ gem "simplecov",">= 0.5"
end
+
+group :test do
+ # gem 'bson_ext'
+end
View
59 Gemfile.lock
@@ -0,0 +1,59 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ activemodel (3.2.6)
+ activesupport (= 3.2.6)
+ builder (~> 3.0.0)
+ activesupport (3.2.6)
+ i18n (~> 0.6)
+ multi_json (~> 1.0)
+ builder (3.0.0)
+ diff-lcs (1.1.3)
+ git (1.2.5)
+ i18n (0.6.0)
+ jeweler (1.8.3)
+ bundler (~> 1.0)
+ git (>= 1.2.5)
+ rake
+ rdoc
+ json (1.7.3)
+ money (5.0.0)
+ i18n (~> 0.4)
+ json
+ mongoid (3.0.0.rc)
+ activemodel (~> 3.1)
+ moped (~> 1.0.0.rc)
+ origin (~> 1.0.0.rc)
+ tzinfo (~> 0.3.22)
+ moped (1.0.0.rc)
+ multi_json (1.3.6)
+ origin (1.0.1)
+ rake (0.9.2.2)
+ rdoc (3.12)
+ json (~> 1.4)
+ rspec (2.10.0)
+ rspec-core (~> 2.10.0)
+ rspec-expectations (~> 2.10.0)
+ rspec-mocks (~> 2.10.0)
+ rspec-core (2.10.1)
+ rspec-expectations (2.10.0)
+ diff-lcs (~> 1.1.3)
+ rspec-mocks (2.10.1)
+ simplecov (0.6.4)
+ multi_json (~> 1.0)
+ simplecov-html (~> 0.5.3)
+ simplecov-html (0.5.3)
+ tzinfo (0.3.33)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ bundler (~> 1.1.0)
+ jeweler (>= 1.8.3)
+ money
+ mongoid (~> 3.0.0.rc)
+ moped
+ rdoc (>= 3.12)
+ rspec (~> 2.10)
+ simplecov (>= 0.5)
View
26 README.rdoc → README.md
@@ -1,8 +1,28 @@
-= money-mongoid
+# Money for mongoid
-Description goes here.
+Use the [money](https://github.com/RubyMoney/money) gem with Mongoid 2.x and 3.x.
-== Contributing to money-mongoid
+## Install
+
+in Gemfile
+
+```ruby
+gem 'money-mongoid'
+```
+
+Bundle via Terminal:
+
+`$ bundle`
+
+## Usage
+
+```ruby
+require 'money-mongoid'
+``
+
+See specs for usage examples, fx `money/mongoid/3x/money_spec.rb`
+
+## Contributing to money-mongoid
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
View
4 Rakefile
@@ -17,8 +17,8 @@ Jeweler::Tasks.new do |gem|
gem.name = "money-mongoid"
gem.homepage = "http://github.com/kristianmandrup/money-mongoid"
gem.license = "MIT"
- gem.summary = %Q{TODO: one-line summary of your gem}
- gem.description = %Q{TODO: longer description of your gem}
+ gem.summary = %Q{Mongoid support and integration for the money gem}
+ gem.description = %Q{Makes it easy to use money with mongoid}
gem.email = "kmandrup@gmail.com"
gem.authors = ["Kristian Mandrup"]
# dependencies defined in Gemfile
View
1  lib/money-mongoid.rb
@@ -0,0 +1 @@
+require 'money/mongoid'
View
16 lib/money/mongoid.rb
@@ -0,0 +1,16 @@
+require 'money/mongoid/core_ext'
+require 'money/orm/generic'
+
+if Mongoid::VERSION > '3'
+ require "money/mongoid/3x/money"
+else
+ require "money/mongoid/2x/money"
+end
+
+module Mongoid
+ module Money
+ class << self
+ attr_accessor :default_polymorphic_money
+ end
+ end
+end
View
22 lib/money/mongoid/2x/money.rb
@@ -0,0 +1,22 @@
+# extend Mongoid::Fields in Mongoid document (model) that wants to use Money
+# this makes Money accessible as a type
+
+module Mongoid
+ module Fields
+ class Money
+ include Mongoid::Fields::Serializable
+
+ def self.instantiate(name, options = {})
+ super
+ end
+
+ def deserialize(value)
+ ::Money.new value[:cents], value[:currency_iso]
+ end
+
+ def serialize(value)
+ {:cents => value.cents, :currency_iso => value.currency.iso_code}
+ end
+ end
+ end
+end
View
38 lib/money/mongoid/3x/money.rb
@@ -0,0 +1,38 @@
+module Mongoize
+ extend ActiveSupport::Concern
+ # See http://mongoid.org/en/mongoid/docs/upgrading.html
+
+ def mongoize
+ {'cents' => cents, 'currency_iso' => currency.iso_code}
+ end
+
+ module ClassMethods
+ def demongoize(value)
+ ::Money.new get_cents(value), get_currency(value)
+ end
+
+ def evolve(object)
+ object.__evolve_to_money__.mongoize
+ end
+
+ private
+
+ def get_cents value
+ value[:cents] || value['cents']
+ end
+
+ def get_currency value
+ value[:currency_iso] || value['currency_iso']
+ end
+ end
+end
+
+
+
+class Money
+ include Mongoize
+
+ def __evolve_to_money__
+ self
+ end
+end
View
2  lib/money/mongoid/core_ext.rb
@@ -0,0 +1,2 @@
+require 'money/mongoid/core_ext/string'
+require 'money/mongoid/core_ext/array'
View
5 lib/money/mongoid/core_ext/array.rb
@@ -0,0 +1,5 @@
+class Array
+ def exchange_to! currency
+ self.map!{|m| m.exchange_to!(currency) }
+ end
+end
View
6 lib/money/mongoid/core_ext/string.rb
@@ -0,0 +1,6 @@
+# encoding: utf-8
+class String
+ def __evolve_to_money__
+ Money.parse(self)
+ end
+end
View
29 lib/money/mongoid/macros.rb
@@ -0,0 +1,29 @@
+module Mongoid
+ module Money
+ module Macros
+ def self.included(base)
+ base.send :include, ClassMethods
+ end
+
+ module ClassMethods
+ def monetize
+ self.send :include, "Mongoid::Monetize".constantize
+ end
+
+ def monetizable options = {}
+ self.send :include, "Mongoid::Monetizable".constantize
+ embedded_in options[:as], :polymorphic => true if options[:as]
+ end
+ end
+ end
+ end
+end
+
+module Mongoid
+ module Document
+ module ClassMethods
+ include Money::Mongoid::Macros
+ end
+ end
+end
+
View
17 lib/money/mongoid/monetizable.rb
@@ -0,0 +1,17 @@
+# Thanks to: https://gist.github.com/840500
+
+module Mongoid
+ module Monetizable
+ include Money::Orm::Generic
+
+ def self.included(base)
+ base.class_eval do
+ field :cents, :type => Integer, :default => 0
+ field :currency_iso, :type => String, :default => ::Money.default_currency.iso_code
+
+ validates_numericality_of :cents
+ end
+ base.extend Money::Orm::Generic::ClassMethods
+ end
+ end
+end
View
35 lib/money/mongoid/monetize.rb
@@ -0,0 +1,35 @@
+module Mongoid
+ module Monetize
+ def self.included(base)
+ base.extend ClassMethods
+ base.extend Money::Orm::Generic::ClassMethods
+ end
+
+ module ClassMethods
+ def monetize_one name, options = {:as => :priced}
+ as_poly = options.delete(:as) || default_polymorphic_money
+
+ unless as_poly
+ raise ArgumentError, "You must set an :as option indicating the polymorphic Monetizable model. See money-rails gem."
+ end
+
+ self.embeds_one name.to_sym, options.merge(:as => as_poly)
+ end
+ alias_method :monetize, :monetize_one
+
+ def monetize_many name, options = {:as => :priced}
+ as_poly = options.delete(:as) || default_polymorphic_money
+ unless as_poly
+ raise ArgumentError, "You must set an :as option indicating the polymorphic Monetizable model. See money-rails gem."
+ end
+ self.embeds_many name, options.merge(:as => as_poly)
+ end
+
+ protected
+
+ def default_polymorphic_money
+ Mongoid::Money.default_polymorphic_money
+ end
+ end # module
+ end
+end
View
24 lib/money/orm/generic.rb
@@ -0,0 +1,24 @@
+class Money
+ module Orm
+ module Generic
+ # Virtual price / currency attributes
+ module ClassMethods
+ def monetize_for *names
+ options = names.last.kind_of?(Hash) ? names.delete(names.last) : {:as => :priced}
+ names.each {|name| monetize name, options }
+ end
+ end
+
+ def price
+ ::Money.new(self.price_pence, currency)
+ end
+ def price=(price)
+ self.price_pence = price.cents
+ end
+
+ def currency
+ ::Money::Currency.new(currency_iso)
+ end
+ end
+ end
+end
View
7 spec/money-mongoid_spec.rb
@@ -1,7 +0,0 @@
-require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
-
-describe "MoneyMongoid" do
- it "fails" do
- fail "hey buddy, you should probably rename this file and start specing for real"
- end
-end
View
14 spec/money/mongoid/2x/money_spec.rb
@@ -0,0 +1,14 @@
+require 'money/mongoid/spec_helper'
+require 'money/mongoid/money'
+require 'money/mongoid/2x/product'
+
+describe 'Mongoid custom Money type' do
+ subject { product }
+
+ let(:product) do { Product.create :price => Money.new(3000, 'USD') }
+
+ its(:price) { should be_a Money }
+
+ specify { subject.price.cents.should == 3000 }
+ specify { subject.price.currency.iso_code.should == 'USD' }
+end
View
6 spec/money/mongoid/2x/product.rb
@@ -0,0 +1,6 @@
+class Product
+ include Mongoid::Document
+ extend Mongoid::Fields # to make Money available!
+
+ field :price, :type => Money
+end
View
49 spec/money/mongoid/3x/money_spec.rb
@@ -0,0 +1,49 @@
+require 'money/mongoid/spec_helper'
+require 'money/mongoid'
+require 'money/mongoid/3x/product'
+
+describe 'Mongoid custom Money type' do
+ subject { product }
+
+ let(:product) { Product.create(:price => Money.new(3000, 'USD')) }
+ let(:products) do
+ end
+
+ its(:price) { should be_a Money }
+
+ specify { subject.price.cents.should == 3000 }
+ specify { subject.price.currency.iso_code.should == 'USD' }
+
+ it "should be searchable by price as money" do
+ Product.create(:price => Money.new(3000, 'USD'))
+ Product.where(price: Money.new(3000, 'USD')).count.should == 1
+ end
+
+ it "should be searchable by price as string" do
+ product
+ Product.where(price: "USD 30.00").count.should == 1
+ end
+
+ it "should be searchable by price using gte and a money value of same currency" do
+ product
+ Product.where(:price.gte => Money.new(2000, 'USD')).count.should == 1
+ end
+
+ it "should be searchable by price using gte and a money value of different currency" do
+ Money.add_rate("USD","EUR", 0.5)
+ Money.add_rate("EUR","USD", 2)
+
+ 6.times do |n|
+ Product.create :price => Money.new(n * 500, 'USD')
+ end
+
+ # So far only works by explicit conversion before search. Any solution?
+ Product.all.exchange_to! 'EUR'
+
+ # puts Product.all.map{|p| p.price.inspect }
+
+ # with our rates 20 EUR -> 40 USD
+ search_res = Product.where :price.gte => Money.new(2000, 'EUR')
+ search_res.count.should == 0
+ end
+end
View
10 spec/money/mongoid/3x/product.rb
@@ -0,0 +1,10 @@
+class Product
+ include Mongoid::Document
+
+ field :price, :type => Money
+
+ def exchange_to! currency_iso
+ self.price = self.price.exchange_to(currency_iso)
+ save
+ end
+end
View
12 spec/money/mongoid/models/account.rb
@@ -0,0 +1,12 @@
+class Account
+ include Mongoid::Document
+ include Mongoid::Monetize
+
+ monetize_for :utility, :services
+
+ embeds_one :deposit, :as => :priced
+ monetize_one :rental_price
+
+ monetize :rent
+ monetize_many :costs, :class_name => 'Price'
+end
View
15 spec/money/mongoid/models/price.rb
@@ -0,0 +1,15 @@
+class Price
+ include Mongoid::Document
+
+ monetizable_orm :mongoid, :as => :priced
+
+ # embedded_in :priced, :polymorphic => true
+
+ def self.for amount, currency = nil
+ currency = ::Money::Currency.new(currency || ::Money.default_currency)
+ money = Money.new(amount, currency)
+
+ # see 'kristianmandrup' fork of money (money/macros)
+ Money::Macros.price_class.new :price => money
+ end
+end
View
87 spec/money/mongoid/monetize_spec.rb
@@ -0,0 +1,87 @@
+require 'money/mongoid/spec_helper'
+
+describe Money::Mongoid::Monetizable do
+ before do
+ Money.default_currency = 'USD'
+ end
+
+ describe "monetize" do
+ subject { account }
+
+ let(:account) do
+ Account.create :rental_price => Price.for(3000, :usd),
+ :deposit => Price.for(150, :usd),
+ :rent => Price.for(100),
+ :utility => priced_at(200),
+ :services => priced_at(150)
+ end
+
+
+ it_behaves_like 'a generic account'
+
+ context 'can add multiple costs' do
+ before do
+ account.costs << Price.for(100, :usd)
+ account.costs << Price.for(200)
+ end
+
+ its(:costs) { should have(2).items }
+ end
+
+ describe 'money macros' do
+ subject { account_2 }
+
+ let(:account_2) do
+ Account.create :rental_price => priced_at(3000, :usd),
+ :deposit => priced_at(150, :usd),
+ :rent => priced_at(100)
+ end
+
+ it_behaves_like 'a generic account'
+ end
+
+ describe 'customize macro map' do
+ context 'set cost_class to Price' do
+ subject { cost_account }
+
+ before do
+ MoneyRails::Moneys.cost_class = Price
+ end
+
+ let(:cost_account) do
+ Account.create :rental_price => costing(3000, :usd)
+ end
+
+ it "rental is money" do
+ subject.rental_price.price.should == Money.new(3000)
+ end
+
+ it "price compare < Numeric" do
+ subject.rental_price.price.should < 3100
+ end
+
+ it "price compare == Numeric" do
+ subject.rental_price.price.should be_eql(3000)
+ end
+
+ it "price compare > Numeric" do
+ subject.rental_price.price.should_not > 3001
+ end
+ end
+
+ context 'set all money classes to Price' do
+ subject { valued_at(4000) }
+
+ before do
+ MoneyRails::Moneys.classes = Price
+ end
+
+ specify { MoneyRails::Moneys.value_class.should == Price }
+
+ specify { subject.should be_a Price }
+ specify { subject.price.should be_a Money }
+ specify { subject.price.should == Money.new(4000) }
+ end
+ end
+ end
+end
View
31 spec/money/mongoid/spec_helper.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+require 'mongoid'
+require 'money'
+
+require 'money/mongoid/version_setup'
+
+Mongoid.configure do |config|
+ Mongoid::VersionSetup.configure config
+end
+
+if RUBY_VERSION >= '1.9.2'
+ YAML::ENGINE.yamler = 'syck'
+end
+
+RSpec.configure do |config|
+ # config.mock_with(:mocha)
+
+ config.before(:each) do
+ Mongoid.purge!
+ # Mongoid.database.collections.each do |collection|
+ # unless collection.name =~ /^system\./
+ # collection.remove
+ # end
+ # end
+ end
+end
+
+# require 'money/mongoid/models/price'
+# require 'money/mongoid/models/account'
+
+# require 'money/shared/generic_account_ex'
View
19 spec/money/mongoid/support/mongoid.yml
@@ -0,0 +1,19 @@
+test:
+ database: money_rails_test
+ host: localhost
+ port: 27017
+ # slaves:
+ # - host: localhost
+ # port: 27018
+ # - host: localhost
+ # port: 27019
+ # allow_dynamic_fields: false
+ # include_root_in_json: true
+ # parameterize_keys: false
+ # persist_in_safe_mode: false
+ # raise_not_found_error: false
+ # reconnect_time: 5
+ # autocreate_indexes: false
+ # persist_types: false
+ # option_no_exist: false
+ # skip_version_check: false
View
37 spec/money/mongoid/version_setup.rb
@@ -0,0 +1,37 @@
+module Mongoid
+ module VersionSetup
+ def self.configure config
+ version = Mongoid::VERSION
+ case
+ when version < '2'
+ raise ArgumentError, "Mongoid versions < 2 not supported"
+ when version < '3'
+ version_2 config
+ when version > '3'
+ version_3 config
+ end
+ end
+
+ def self.version_3 config
+ require 'moped'
+ config.connect_to('money_mongoid_test')
+ end
+
+ def self.version_2 config
+ require 'bson'
+
+ opts = YAML.load(File.read(File.dirname(__FILE__) + '/support/mongoid.yml'))["test"]
+ opts.delete("slaves") # no slaves support for version < 3
+ name = opts.delete("database")
+ host = opts.delete("host")
+ port = opts.delete("port")
+ config.master = begin
+ Mongo::Connection.new(host, port, opts).db(name)
+ rescue Mongo::ConnectionFailure
+ Mongo::Connection.new(host, '27017', opts).db(name)
+ end
+ config.logger = nil
+ config.allow_dynamic_fields = true
+ end
+ end
+end
View
10 spec/spec_helper.rb
@@ -1,12 +1,4 @@
-$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'rspec'
-require 'money-mongoid'
-# Requires supporting files with custom matchers and macros, etc,
-# in ./support/ and its subdirectories.
-Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
+SPEC_DIR = File.dirname(__FILE__)
-RSpec.configure do |config|
-
-end
Please sign in to comment.
Something went wrong with that request. Please try again.