opium 1.0.0.beta

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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +24 -0
  4. data/.travis.yml +17 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +11 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +71 -0
  9. data/Rakefile +10 -0
  10. data/lib/generators/opium/config_generator.rb +15 -0
  11. data/lib/generators/opium/model_generator.rb +33 -0
  12. data/lib/generators/opium/templates/config.yml +27 -0
  13. data/lib/generators/opium/templates/model.rb +10 -0
  14. data/lib/opium/config.rb +44 -0
  15. data/lib/opium/extensions/array.rb +10 -0
  16. data/lib/opium/extensions/boolean.rb +13 -0
  17. data/lib/opium/extensions/date.rb +18 -0
  18. data/lib/opium/extensions/date_time.rb +18 -0
  19. data/lib/opium/extensions/false_class.rb +7 -0
  20. data/lib/opium/extensions/float.rb +13 -0
  21. data/lib/opium/extensions/geo_point.rb +37 -0
  22. data/lib/opium/extensions/hash.rb +43 -0
  23. data/lib/opium/extensions/integer.rb +13 -0
  24. data/lib/opium/extensions/numeric.rb +7 -0
  25. data/lib/opium/extensions/object.rb +15 -0
  26. data/lib/opium/extensions/pointer.rb +20 -0
  27. data/lib/opium/extensions/regexp.rb +12 -0
  28. data/lib/opium/extensions/string.rb +20 -0
  29. data/lib/opium/extensions/time.rb +19 -0
  30. data/lib/opium/extensions/true_class.rb +7 -0
  31. data/lib/opium/extensions.rb +16 -0
  32. data/lib/opium/model/attributable.rb +37 -0
  33. data/lib/opium/model/callbacks.rb +38 -0
  34. data/lib/opium/model/connectable.rb +155 -0
  35. data/lib/opium/model/criteria.rb +123 -0
  36. data/lib/opium/model/dirty.rb +35 -0
  37. data/lib/opium/model/field.rb +31 -0
  38. data/lib/opium/model/fieldable.rb +57 -0
  39. data/lib/opium/model/findable.rb +20 -0
  40. data/lib/opium/model/kaminari/queryable.rb +46 -0
  41. data/lib/opium/model/kaminari/scopable.rb +15 -0
  42. data/lib/opium/model/kaminari.rb +4 -0
  43. data/lib/opium/model/persistable.rb +153 -0
  44. data/lib/opium/model/queryable.rb +150 -0
  45. data/lib/opium/model/scopable.rb +58 -0
  46. data/lib/opium/model/serialization.rb +13 -0
  47. data/lib/opium/model.rb +47 -0
  48. data/lib/opium/railtie.rb +14 -0
  49. data/lib/opium/user.rb +44 -0
  50. data/lib/opium/version.rb +3 -0
  51. data/lib/opium.rb +9 -0
  52. data/opium.gemspec +40 -0
  53. data/spec/opium/config/opium.yml +5 -0
  54. data/spec/opium/config_spec.rb +56 -0
  55. data/spec/opium/extensions/array_spec.rb +34 -0
  56. data/spec/opium/extensions/boolean_spec.rb +28 -0
  57. data/spec/opium/extensions/date_spec.rb +55 -0
  58. data/spec/opium/extensions/date_time_spec.rb +55 -0
  59. data/spec/opium/extensions/float_spec.rb +42 -0
  60. data/spec/opium/extensions/geo_point_spec.rb +55 -0
  61. data/spec/opium/extensions/hash_spec.rb +76 -0
  62. data/spec/opium/extensions/integer_spec.rb +42 -0
  63. data/spec/opium/extensions/object_spec.rb +24 -0
  64. data/spec/opium/extensions/pointer_spec.rb +28 -0
  65. data/spec/opium/extensions/regexp_spec.rb +23 -0
  66. data/spec/opium/extensions/string_spec.rb +65 -0
  67. data/spec/opium/extensions/time_spec.rb +55 -0
  68. data/spec/opium/model/attributable_spec.rb +45 -0
  69. data/spec/opium/model/callbacks_spec.rb +59 -0
  70. data/spec/opium/model/connectable_spec.rb +218 -0
  71. data/spec/opium/model/criteria_spec.rb +285 -0
  72. data/spec/opium/model/dirty_spec.rb +39 -0
  73. data/spec/opium/model/fieldable_spec.rb +133 -0
  74. data/spec/opium/model/findable_spec.rb +57 -0
  75. data/spec/opium/model/kaminari/queryable_spec.rb +22 -0
  76. data/spec/opium/model/kaminari/scopable_spec.rb +20 -0
  77. data/spec/opium/model/kaminari_spec.rb +104 -0
  78. data/spec/opium/model/persistable_spec.rb +367 -0
  79. data/spec/opium/model/queryable_spec.rb +338 -0
  80. data/spec/opium/model/scopable_spec.rb +115 -0
  81. data/spec/opium/model/serialization_spec.rb +51 -0
  82. data/spec/opium/model_spec.rb +49 -0
  83. data/spec/opium/user_spec.rb +195 -0
  84. data/spec/opium_spec.rb +5 -0
  85. data/spec/spec_helper.rb +25 -0
  86. metadata +400 -0
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe GeoPoint do
4
+ subject { GeoPoint }
5
+
6
+ it { should respond_to(:to_ruby, :to_parse).with(1).argument }
7
+
8
+ it ":to_ruby(object) should create a GeoPoint" do
9
+ [ "33.33, -117.117", {latitude: 33.33, longitude: -117.117}, [33.33, -117.117], GeoPoint.new( [33.33, -117.117] ) ].each do |value|
10
+ result = subject.to_ruby( value )
11
+ result.should be_a_kind_of(GeoPoint)
12
+ result.latitude.should == 33.33
13
+ result.longitude.should == -117.117
14
+ end
15
+ end
16
+
17
+ it ":to_ruby(bad_data) should raise exception" do
18
+ [ "malformed", {latitude: 0, bad_key: :unknown}, [0], 1, 1.0, true, false ].each do |value|
19
+ expect { subject.to_ruby( value ) }.to raise_exception
20
+ end
21
+ end
22
+
23
+ it ":to_parse(object) should ensure a geo_point and make into parse object" do
24
+ [ "33.33, -117.117", {latitude: 33.33, longitude: -117.117}, [33.33, -117.117], GeoPoint.new( [33.33, -117.117] ) ].each do |value|
25
+ result = subject.to_parse( value )
26
+ result.should == { "__type" => "GeoPoint", "latitude" => 33.33, "longitude" => -117.117 }
27
+ end
28
+ end
29
+
30
+ describe "instance" do
31
+ describe "with an array value" do
32
+ subject { GeoPoint.new [33.33, -117.117] }
33
+ it { should respond_to(:latitude, :longitude, :to_geo_point, :to_parse).with(0).arguments }
34
+ it { should respond_to(:latitude=, :longitude=).with(1).argument }
35
+
36
+ its(:latitude) { should == 33.33 }
37
+ its(:longitude) { should == -117.117 }
38
+ its(:to_geo_point) { should == subject }
39
+ its(:to_parse) { should == { "__type" => "GeoPoint", "latitude" => 33.33, "longitude" => -117.117 } }
40
+ its(:to_s) { should == "33.33,-117.117" }
41
+ end
42
+
43
+ describe "with a hash value" do
44
+ subject { GeoPoint.new latitude: 33.33, longitude: -117.117 }
45
+ it { should respond_to(:latitude, :longitude, :to_geo_point, :to_parse).with(0).arguments }
46
+ it { should respond_to(:latitude=, :longitude=).with(1).argument }
47
+
48
+ its(:latitude) { should == 33.33 }
49
+ its(:longitude) { should == -117.117 }
50
+ its(:to_geo_point) { should == subject }
51
+ its(:to_parse) { should == { "__type" => "GeoPoint", "latitude" => 33.33, "longitude" => -117.117 } }
52
+ its(:to_s) { should == "33.33,-117.117" }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash do
4
+ subject { Hash }
5
+
6
+ describe "instance" do
7
+ describe ":to_parse" do
8
+ subject { { 'foo' => GeoPoint.new( latitude: 33.33, longitude: -117.117 ) } }
9
+
10
+ it 'should return a new hash, with :to_parse called on each value' do
11
+ subject.to_parse.tap do |result|
12
+ result.should =~ { 'foo' => { '__type' => 'GeoPoint', 'latitude' => 33.33, 'longitude' => -117.117 } }
13
+ end
14
+ end
15
+ end
16
+
17
+ describe "with latitude and longitude keys" do
18
+ describe ":to_geo_point" do
19
+ subject { { latitude: 33.33, longitude: -117.117 } }
20
+
21
+ it { subject.to_geo_point.should be_a_kind_of(GeoPoint) }
22
+ it "should have the expected latitude and longitude" do
23
+ subject.to_geo_point.latitude.should == 33.33
24
+ subject.to_geo_point.longitude.should == -117.117
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "without latitude or longitude keys" do
30
+ describe ":to_geo_point" do
31
+ subject { { latitude: 33.33 } }
32
+
33
+ it { expect { subject.to_geo_point }.to raise_exception }
34
+ end
35
+ end
36
+
37
+ describe "with __type key" do
38
+ describe "of Date" do
39
+ describe "with iso key" do
40
+ subject { { '__type' => 'Date', 'iso' => DateTime.now.iso8601 } }
41
+
42
+ describe ":to_datetime" do
43
+ let(:result) { subject.to_datetime }
44
+ it { result.should be_a_kind_of( DateTime ) }
45
+ end
46
+
47
+ describe ":to_date" do
48
+ let(:result) { subject.to_date }
49
+ it { result.should be_a_kind_of( Date ) }
50
+ end
51
+
52
+ describe ":to_time" do
53
+ let(:result) { subject.to_time }
54
+ it { result.should be_a_kind_of( Time ) }
55
+ end
56
+ end
57
+
58
+ describe "without iso key" do
59
+ subject { { '__type' => 'Date' } }
60
+
61
+ describe ":to_datetime" do
62
+ it { expect { subject.to_datetime }.to raise_exception }
63
+ end
64
+
65
+ describe ":to_date" do
66
+ it { expect { subject.to_datetime }.to raise_exception }
67
+ end
68
+
69
+ describe ":to_time" do
70
+ it { expect { subject.to_datetime }.to raise_exception }
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Integer do
4
+ subject { Integer }
5
+ it { should respond_to(:to_ruby).with(1).argument }
6
+ it { should respond_to(:to_parse).with(1).argument }
7
+
8
+ it ":to_ruby(object) should convert object to a integer" do
9
+ {nil => nil, :foo => :foo.to_s.to_i}.each do |value, expected|
10
+ subject.to_ruby(value).should be_a_kind_of(expected.class)
11
+ subject.to_ruby(value).should == expected
12
+ end
13
+ ["foo", 42.0, 42, Time.now].each do |value|
14
+ subject.to_ruby(value).should be_a_kind_of(Integer)
15
+ subject.to_ruby(value).should == value.to_i
16
+ end
17
+ end
18
+
19
+ it ":to_parse(object) should convert object to a integer" do
20
+ {nil => nil, :foo => :foo.to_s.to_i}.each do |value, expected|
21
+ subject.to_parse(value).should be_a_kind_of(expected.class)
22
+ subject.to_parse(value).should == expected
23
+ end
24
+ ["foo", 42.0, 42, Time.now].each do |value|
25
+ subject.to_parse(value).should be_a_kind_of(Integer)
26
+ subject.to_parse(value).should == value.to_i
27
+ end
28
+ end
29
+
30
+ describe "instance" do
31
+ subject { 42 }
32
+ it { should respond_to(:to_ruby, :to_parse, :to_bool).with(0).arguments }
33
+ its(:to_ruby) { should == subject }
34
+ its(:to_parse) { should == subject }
35
+
36
+ it "should convert 1 and 0 to true and false, all others raise" do
37
+ 1.to_bool.should == true
38
+ 0.to_bool.should == false
39
+ expect { subject.to_bool }.to raise_exception
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Object do
4
+ subject { Object }
5
+ it { should respond_to(:to_parse).with(1).argument }
6
+ it { should respond_to(:to_ruby).with(1).argument }
7
+
8
+ it ":to_parse(object) should return the object" do
9
+ object = subject.new
10
+ subject.to_parse(object).should == object
11
+ end
12
+
13
+ it ":to_ruby(object) should return the object" do
14
+ object = subject.new
15
+ subject.to_ruby(object).should == object
16
+ end
17
+
18
+ describe "instance" do
19
+ subject { Object.new }
20
+ it { should respond_to(:to_parse, :to_ruby) }
21
+ its(:to_parse) { should == subject }
22
+ its(:to_ruby) { should == subject }
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Opium::Pointer do
4
+ subject { Opium::Pointer }
5
+
6
+ describe 'an instance' do
7
+ subject { Opium::Pointer.new( model_name: 'Game', id: 'abcd1234' ) }
8
+
9
+ it { should respond_to( :model_name, :class_name, :id, :to_parse ) }
10
+
11
+ describe ':model_name' do
12
+ it 'should be an alias of :class_name' do
13
+ subject.method(:model_name).should == subject.method(:class_name)
14
+ end
15
+ end
16
+
17
+ describe ':to_parse' do
18
+ it 'should be a hash' do
19
+ subject.to_parse.should be_a( Hash )
20
+ end
21
+
22
+ it 'should have keys for "__type", "objectId", and "className"' do
23
+ subject.to_parse.keys.should =~ [ '__type', 'objectId', 'className' ]
24
+ subject.to_parse.should =~ { '__type' => 'Pointer', 'objectId' => 'abcd1234', 'className' => 'Game' }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe /foo/ do
4
+
5
+ it { should respond_to( :to_parse ) }
6
+
7
+ describe ':to_parse' do
8
+ it 'should create a hash containing a $regex key containing the regexp source' do
9
+ /foo.?bar/.to_parse.tap do |result|
10
+ result.should be_a( Hash )
11
+ result.should have_key( '$regex' )
12
+ result['$regex'].should == 'foo.?bar'
13
+ end
14
+ end
15
+
16
+ it 'should also contain an $options key for any options defined on the regexp' do
17
+ /foo.?bar/ix.to_parse.tap do |result|
18
+ result.should have_key( '$options' )
19
+ result['$options'].should == 'ix'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe String do
4
+ subject { String }
5
+ it { should respond_to(:to_ruby).with(1).argument }
6
+ it { should respond_to(:to_parse).with(1).argument }
7
+
8
+ it ":to_ruby(object) should convert object to a string" do
9
+ {nil => nil}.each do |value, expected|
10
+ subject.to_ruby(value).should be_a_kind_of(expected.class)
11
+ subject.to_ruby(value).should == expected
12
+ end
13
+ [:foo, "foo", 42.0, 42, Time.now].each do |value|
14
+ subject.to_ruby(value).should be_a_kind_of(String)
15
+ subject.to_ruby(value).should == value.to_s
16
+ end
17
+ end
18
+
19
+ it ":to_parse(object) should convert object to a string" do
20
+ {nil => nil}.each do |value, expected|
21
+ subject.to_parse(value).should be_a_kind_of(expected.class)
22
+ subject.to_parse(value).should == expected
23
+ end
24
+ [:foo, "foo", 42.0, 42, Time.now].each do |value|
25
+ subject.to_parse(value).should be_a_kind_of(String)
26
+ subject.to_parse(value).should == value.to_s
27
+ end
28
+ end
29
+
30
+ describe "instance" do
31
+ subject { "instance" }
32
+ it { should respond_to(:to_ruby, :to_parse, :to_bool, :to_geo_point).with(0).arguments }
33
+ its(:to_ruby) { should == subject }
34
+ its(:to_parse) { should == subject }
35
+
36
+ it "should be able to convert various values to true" do
37
+ %w[true t yes y 1].each do |value|
38
+ value.to_bool.should be_a_kind_of( Boolean )
39
+ value.to_bool.should == true
40
+ end
41
+ end
42
+
43
+ it "should be able to convert various values to false" do
44
+ [""] + %w[false f no n 0].each do |value|
45
+ value.to_bool.should be_a_kind_of( Boolean )
46
+ value.to_bool.should == false
47
+ end
48
+ end
49
+
50
+ it "any non-boolean string should raise on :to_bool" do
51
+ expect { subject.to_bool }.to raise_exception
52
+ end
53
+
54
+ it ":to_geo_point should be able to convert a 'lat, lng' value" do
55
+ result = "33.33, -117.117".to_geo_point
56
+ result.should be_a_kind_of(GeoPoint)
57
+ result.latitude.should == 33.33
58
+ result.longitude.should == -117.117
59
+ end
60
+
61
+ it ":to_geo_point should raise exception if invalid" do
62
+ expect { "malformed".to_geo_point }.to raise_exception
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Time do
4
+ subject { Time }
5
+ it { should respond_to(:to_parse, :to_ruby).with(1).argument }
6
+
7
+ describe ":to_ruby" do
8
+ describe "with a Hash containing '__type: Date'" do
9
+ let(:object) { { '__type' => 'Date', 'iso' => Time.now.iso8601 } }
10
+ it { subject.to_ruby(object).should be_a_kind_of( Time ) }
11
+ end
12
+
13
+ describe "with a Hash without a '__type' key" do
14
+ let(:object) { { 'iso' => Time.now.iso8601 } }
15
+ it { expect { subject.to_ruby(object) }.to raise_exception }
16
+ end
17
+
18
+ describe "with an object which responds to :to_time" do
19
+ let(:objects) { [ Time.now.iso8601, DateTime.now, Time.now, Date.today ] }
20
+ it do
21
+ objects.each do |object|
22
+ subject.to_ruby(object).should be_a_kind_of( Time )
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ describe ":to_parse(object)" do
29
+ let(:objects) { [ Time.now.iso8601, DateTime.now, Time.now, Date.today ] }
30
+ it "should ensure that the object is a datetime" do
31
+ objects.each do |object|
32
+ object.should_receive :to_time
33
+ subject.to_parse(object)
34
+ end
35
+ end
36
+
37
+ it "should make a parse object hash" do
38
+ objects.each do |object|
39
+ result = subject.to_parse(object)
40
+ result.should be_a_kind_of(Hash)
41
+ result.keys.should == ['__type', 'iso']
42
+ result['__type'].should == 'Date'
43
+ end
44
+ end
45
+ end
46
+
47
+ describe "instance" do
48
+ subject { Time.now }
49
+ let(:result) { subject.to_parse }
50
+ it { result.should be_a_kind_of(Hash) }
51
+ it { result.keys.should == ['__type', 'iso'] }
52
+ it { result['__type'].should == 'Date' }
53
+ it { result['iso'].should == subject.iso8601 }
54
+ end
55
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Opium::Model::Attributable do
4
+ let( :model ) { Class.new { include Opium::Model::Attributable } }
5
+
6
+ describe 'instance' do
7
+ subject { model.new }
8
+
9
+ it { should respond_to( :attributes, :attributes= ) }
10
+ it { should respond_to( :attributes_to_parse ) }
11
+ end
12
+
13
+ describe 'when included in a model' do
14
+ before do
15
+ stub_const( 'Book', Class.new do
16
+ include Opium::Model
17
+ field :title, type: String
18
+ end )
19
+ end
20
+
21
+ subject { Book.new( title: 'Little Brother', id: 'abc123', created_at: Time.now ) }
22
+
23
+ describe 'attributes_to_parse' do
24
+ it 'when called with no parameters, should have all fields present, with names and values converted to parse' do
25
+ subject.attributes_to_parse.should =~ { 'objectId' => 'abc123', 'title' => 'Little Brother', 'createdAt' => subject.created_at.to_parse, 'updatedAt' => nil }
26
+ end
27
+
28
+ it 'when called with except, should exclude the excepted fields' do
29
+ subject.attributes_to_parse( except: [:id, :updated_at] ).should =~ { 'title' => 'Little Brother', 'createdAt' => subject.created_at.to_parse }
30
+ end
31
+
32
+ it 'when called with not_readonly, should exclude all readonly fields' do
33
+ subject.attributes_to_parse( not_readonly: true ).should =~ { 'title' => 'Little Brother' }
34
+ end
35
+ end
36
+
37
+ describe ':attributes=' do
38
+ it 'should still store unrecognized fields in the attributes hash' do
39
+ expect { subject.attributes = { unknownField: 42 } }.to_not raise_exception
40
+ subject.attributes.should have_key('unknownField')
41
+ subject.attributes['unknownField'].should == 42
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Opium::Model::Callbacks do
4
+ let( :model ) {
5
+ Class.new do
6
+ def initialize( a = {} ) end
7
+ def save( o = {} ) end
8
+ def destroy; end
9
+ def touch; end
10
+ def create; end
11
+ def update; end
12
+ def find( id ) end
13
+
14
+ private :create, :update
15
+
16
+ include Opium::Model::Callbacks
17
+ end
18
+ }
19
+
20
+ its( :constants ) { should include(:CALLBACKS) }
21
+
22
+ it "should provide a list of its defined CALLBACKS" do
23
+ subject::CALLBACKS.should_not be_nil
24
+ subject::CALLBACKS.should_not be_empty
25
+ end
26
+
27
+ it "should respond to each of its CALLBACKS" do
28
+ subject::CALLBACKS.each do |callback|
29
+ model.should respond_to(callback)
30
+ end
31
+ end
32
+
33
+ shared_examples_for 'its callbacks should be invoked for' do |method, options = {}|
34
+ describe method do
35
+ subject { model.new }
36
+
37
+ it 'should run callbacks' do
38
+ subject.should receive(:run_callbacks).with(method)
39
+ subject.send(method, *options[:args])
40
+ end
41
+
42
+ it 'should not make a private method public' do
43
+ if options[:private]
44
+ subject.should_not respond_to(method)
45
+ else
46
+ subject.should respond_to(method)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ it_should_behave_like 'its callbacks should be invoked for', :initialize, private: true
53
+ it_should_behave_like 'its callbacks should be invoked for', :save
54
+ it_should_behave_like 'its callbacks should be invoked for', :create, private: true
55
+ it_should_behave_like 'its callbacks should be invoked for', :update, private: true
56
+ it_should_behave_like 'its callbacks should be invoked for', :destroy
57
+ it_should_behave_like 'its callbacks should be invoked for', :touch
58
+ it_should_behave_like 'its callbacks should be invoked for', :find, args: ['abcd1234']
59
+ end