restorm 1.0.0

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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +31 -0
  5. data/.rubocop_todo.yml +232 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +55 -0
  8. data/.yardopts +2 -0
  9. data/CONTRIBUTING.md +26 -0
  10. data/Gemfile +10 -0
  11. data/HER_README.md +1065 -0
  12. data/LICENSE +7 -0
  13. data/README.md +7 -0
  14. data/Rakefile +11 -0
  15. data/UPGRADE.md +101 -0
  16. data/gemfiles/Gemfile.activemodel-4.2 +6 -0
  17. data/gemfiles/Gemfile.activemodel-5.0 +6 -0
  18. data/gemfiles/Gemfile.activemodel-5.1 +6 -0
  19. data/gemfiles/Gemfile.activemodel-5.2 +6 -0
  20. data/gemfiles/Gemfile.faraday-1.0 +6 -0
  21. data/lib/restorm/api.rb +121 -0
  22. data/lib/restorm/collection.rb +13 -0
  23. data/lib/restorm/errors.rb +29 -0
  24. data/lib/restorm/json_api/model.rb +42 -0
  25. data/lib/restorm/middleware/accept_json.rb +18 -0
  26. data/lib/restorm/middleware/first_level_parse_json.rb +37 -0
  27. data/lib/restorm/middleware/json_api_parser.rb +37 -0
  28. data/lib/restorm/middleware/parse_json.rb +22 -0
  29. data/lib/restorm/middleware/second_level_parse_json.rb +37 -0
  30. data/lib/restorm/middleware.rb +12 -0
  31. data/lib/restorm/model/associations/association.rb +128 -0
  32. data/lib/restorm/model/associations/association_proxy.rb +44 -0
  33. data/lib/restorm/model/associations/belongs_to_association.rb +95 -0
  34. data/lib/restorm/model/associations/has_many_association.rb +100 -0
  35. data/lib/restorm/model/associations/has_one_association.rb +79 -0
  36. data/lib/restorm/model/associations.rb +141 -0
  37. data/lib/restorm/model/attributes.rb +322 -0
  38. data/lib/restorm/model/base.rb +33 -0
  39. data/lib/restorm/model/deprecated_methods.rb +61 -0
  40. data/lib/restorm/model/http.rb +119 -0
  41. data/lib/restorm/model/introspection.rb +67 -0
  42. data/lib/restorm/model/nested_attributes.rb +45 -0
  43. data/lib/restorm/model/orm.rb +299 -0
  44. data/lib/restorm/model/parse.rb +223 -0
  45. data/lib/restorm/model/paths.rb +125 -0
  46. data/lib/restorm/model/relation.rb +209 -0
  47. data/lib/restorm/model.rb +75 -0
  48. data/lib/restorm/version.rb +3 -0
  49. data/lib/restorm.rb +19 -0
  50. data/restorm.gemspec +29 -0
  51. data/spec/api_spec.rb +120 -0
  52. data/spec/collection_spec.rb +41 -0
  53. data/spec/json_api/model_spec.rb +169 -0
  54. data/spec/middleware/accept_json_spec.rb +11 -0
  55. data/spec/middleware/first_level_parse_json_spec.rb +63 -0
  56. data/spec/middleware/json_api_parser_spec.rb +52 -0
  57. data/spec/middleware/second_level_parse_json_spec.rb +35 -0
  58. data/spec/model/associations/association_proxy_spec.rb +29 -0
  59. data/spec/model/associations_spec.rb +911 -0
  60. data/spec/model/attributes_spec.rb +354 -0
  61. data/spec/model/callbacks_spec.rb +176 -0
  62. data/spec/model/dirty_spec.rb +133 -0
  63. data/spec/model/http_spec.rb +201 -0
  64. data/spec/model/introspection_spec.rb +81 -0
  65. data/spec/model/nested_attributes_spec.rb +135 -0
  66. data/spec/model/orm_spec.rb +704 -0
  67. data/spec/model/parse_spec.rb +520 -0
  68. data/spec/model/paths_spec.rb +348 -0
  69. data/spec/model/relation_spec.rb +247 -0
  70. data/spec/model/validations_spec.rb +43 -0
  71. data/spec/model_spec.rb +45 -0
  72. data/spec/spec_helper.rb +25 -0
  73. data/spec/support/macros/her_macros.rb +17 -0
  74. data/spec/support/macros/model_macros.rb +36 -0
  75. data/spec/support/macros/request_macros.rb +27 -0
  76. metadata +203 -0
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Restorm::Middleware::FirstLevelParseJSON do
6
+ subject { described_class.new }
7
+ let(:body_without_errors) { "{\"id\": 1, \"name\": \"Tobias Fünke\", \"metadata\": 3}" }
8
+ let(:body_with_errors) { "{\"id\": 1, \"name\": \"Tobias Fünke\", \"errors\": { \"name\": [ \"not_valid\", \"should_be_present\" ] }, \"metadata\": 3}" }
9
+ let(:body_with_malformed_json) { "wut." }
10
+ let(:body_with_invalid_json) { "true" }
11
+ let(:empty_body) { "" }
12
+ let(:nil_body) { nil }
13
+
14
+ it "parses body as json" do
15
+ subject.parse(body_without_errors).tap do |json|
16
+ expect(json[:data]).to eq(id: 1, name: "Tobias Fünke")
17
+ expect(json[:metadata]).to eq(3)
18
+ end
19
+ end
20
+
21
+ it "parses :body key as json in the env hash" do
22
+ env = { body: body_without_errors }
23
+ subject.on_complete(env)
24
+ env[:body].tap do |json|
25
+ expect(json[:data]).to eq(id: 1, name: "Tobias Fünke")
26
+ expect(json[:metadata]).to eq(3)
27
+ end
28
+ end
29
+
30
+ it "ensures the errors are a hash if there are no errors" do
31
+ expect(subject.parse(body_without_errors)[:errors]).to eq({})
32
+ end
33
+
34
+ it "ensures the errors are a hash if there are no errors" do
35
+ expect(subject.parse(body_with_errors)[:errors]).to eq(name: %w[not_valid should_be_present])
36
+ end
37
+
38
+ it "ensures that malformed JSON throws an exception" do
39
+ expect { subject.parse(body_with_malformed_json) }.to raise_error(Restorm::Errors::ParseError, 'Response from the API must behave like a Hash or an Array (last JSON response was "wut.")')
40
+ end
41
+
42
+ it "ensures that invalid JSON throws an exception" do
43
+ expect { subject.parse(body_with_invalid_json) }.to raise_error(Restorm::Errors::ParseError, 'Response from the API must behave like a Hash or an Array (last JSON response was "true")')
44
+ end
45
+
46
+ it "ensures that a nil response returns an empty hash" do
47
+ expect(subject.parse(nil_body)[:data]).to eq({})
48
+ end
49
+
50
+ it "ensures that an empty response returns an empty hash" do
51
+ expect(subject.parse(empty_body)[:data]).to eq({})
52
+ end
53
+
54
+ context "with status code 204" do
55
+ it "returns an empty body" do
56
+ env = { status: 204 }
57
+ subject.on_complete(env)
58
+ env[:body].tap do |json|
59
+ expect(json[:data]).to eq({})
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Restorm::Middleware::JsonApiParser do
6
+ subject { described_class.new }
7
+
8
+ context "with valid JSON body" do
9
+ let(:body) { '{"data": {"type": "foo", "id": "bar", "attributes": {"baz": "qux"} }, "meta": {"api": "json api"} }' }
10
+ let(:env) { { body: body } }
11
+
12
+ it "parses body as json" do
13
+ subject.on_complete(env)
14
+ env.fetch(:body).tap do |json|
15
+ expect(json[:data]).to eql(
16
+ type: "foo",
17
+ id: "bar",
18
+ attributes: { baz: "qux" }
19
+ )
20
+ expect(json[:errors]).to eql([])
21
+ expect(json[:metadata]).to eql(api: "json api")
22
+ end
23
+ end
24
+ end
25
+
26
+ context "with status code 204" do
27
+ it "returns an empty body" do
28
+ env = { status: 204 }
29
+ subject.on_complete(env)
30
+ env[:body].tap do |json|
31
+ expect(json[:data]).to eq({})
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'with status code 304' do
37
+ it 'returns an empty body' do
38
+ env = { :status => 304 }
39
+ subject.on_complete(env)
40
+ env[:body].tap do |json|
41
+ expect(json[:data]).to eq({})
42
+ end
43
+ end
44
+ end
45
+
46
+ # context "with invalid JSON body" do
47
+ # let(:body) { '"foo"' }
48
+ # it 'ensures that invalid JSON throws an exception' do
49
+ # expect { subject.parse(body) }.to raise_error(Restorm::Errors::ParseError, 'Response from the API must behave like a Hash or an Array (last JSON response was "\"foo\"")')
50
+ # end
51
+ # end
52
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Restorm::Middleware::SecondLevelParseJSON do
6
+ subject { described_class.new }
7
+
8
+ context "with valid JSON body" do
9
+ let(:body) { "{\"data\": 1, \"errors\": 2, \"metadata\": 3}" }
10
+ it "parses body as json" do
11
+ subject.parse(body).tap do |json|
12
+ expect(json[:data]).to eq(1)
13
+ expect(json[:errors]).to eq(2)
14
+ expect(json[:metadata]).to eq(3)
15
+ end
16
+ end
17
+
18
+ it "parses :body key as json in the env hash" do
19
+ env = { body: body }
20
+ subject.on_complete(env)
21
+ env[:body].tap do |json|
22
+ expect(json[:data]).to eq(1)
23
+ expect(json[:errors]).to eq(2)
24
+ expect(json[:metadata]).to eq(3)
25
+ end
26
+ end
27
+ end
28
+
29
+ context "with invalid JSON body" do
30
+ let(:body) { '"foo"' }
31
+ it "ensures that invalid JSON throws an exception" do
32
+ expect { subject.parse(body) }.to raise_error(Restorm::Errors::ParseError, 'Response from the API must behave like a Hash or an Array (last JSON response was "\"foo\"")')
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Restorm::Model::Associations::AssociationProxy do
6
+ describe "proxy assignment methods" do
7
+ before do
8
+ Restorm::API.setup url: "https://api.example.com" do |builder|
9
+ builder.use Restorm::Middleware::FirstLevelParseJSON
10
+ builder.use Faraday::Request::UrlEncoded
11
+ builder.adapter :test do |stub|
12
+ stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke" }.to_json] }
13
+ stub.get("/users/1/fish") { [200, {}, { id: 1, name: "Tobias's Fish" }.to_json] }
14
+ end
15
+ end
16
+ spawn_model "User" do
17
+ has_one :fish
18
+ end
19
+ spawn_model "Fish"
20
+ end
21
+
22
+ subject { User.find(1) }
23
+
24
+ it "should assign value" do
25
+ subject.fish.name = "Fishy"
26
+ expect(subject.fish.name).to eq "Fishy"
27
+ end
28
+ end
29
+ end