atum 0.5.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 +16 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +9 -0
  5. data/.rubocop_todo.yml +25 -0
  6. data/.travis.yml +9 -0
  7. data/Appraisals +9 -0
  8. data/CHANGELOG.md +5 -0
  9. data/CONTRIBUTING.md +9 -0
  10. data/CONTRIBUTORS.md +15 -0
  11. data/Gemfile +4 -0
  12. data/Guardfile +23 -0
  13. data/LICENSE.txt +22 -0
  14. data/README.md +95 -0
  15. data/Rakefile +13 -0
  16. data/TODO +3 -0
  17. data/atum.gemspec +37 -0
  18. data/bin/atum +41 -0
  19. data/circle.yml +7 -0
  20. data/gemfiles/faraday_0.8.9.gemfile +8 -0
  21. data/gemfiles/faraday_0.9.gemfile +8 -0
  22. data/lib/atum.rb +15 -0
  23. data/lib/atum/core.rb +13 -0
  24. data/lib/atum/core/client.rb +45 -0
  25. data/lib/atum/core/errors.rb +20 -0
  26. data/lib/atum/core/link.rb +77 -0
  27. data/lib/atum/core/paginator.rb +32 -0
  28. data/lib/atum/core/request.rb +55 -0
  29. data/lib/atum/core/resource.rb +15 -0
  30. data/lib/atum/core/response.rb +53 -0
  31. data/lib/atum/core/schema.rb +12 -0
  32. data/lib/atum/core/schema/api_schema.rb +62 -0
  33. data/lib/atum/core/schema/link_schema.rb +121 -0
  34. data/lib/atum/core/schema/parameter.rb +27 -0
  35. data/lib/atum/core/schema/parameter_choice.rb +28 -0
  36. data/lib/atum/core/schema/resource_schema.rb +51 -0
  37. data/lib/atum/generation.rb +15 -0
  38. data/lib/atum/generation/erb_context.rb +17 -0
  39. data/lib/atum/generation/errors.rb +6 -0
  40. data/lib/atum/generation/generator_link.rb +39 -0
  41. data/lib/atum/generation/generator_resource.rb +31 -0
  42. data/lib/atum/generation/generator_service.rb +73 -0
  43. data/lib/atum/generation/generators/base_generator.rb +57 -0
  44. data/lib/atum/generation/generators/client_generator.rb +16 -0
  45. data/lib/atum/generation/generators/module_generator.rb +17 -0
  46. data/lib/atum/generation/generators/resource_generator.rb +23 -0
  47. data/lib/atum/generation/generators/views/client.erb +26 -0
  48. data/lib/atum/generation/generators/views/module.erb +104 -0
  49. data/lib/atum/generation/generators/views/resource.erb +33 -0
  50. data/lib/atum/generation/options_parameter.rb +12 -0
  51. data/lib/atum/version.rb +3 -0
  52. data/spec/atum/core/client_spec.rb +26 -0
  53. data/spec/atum/core/errors_spec.rb +19 -0
  54. data/spec/atum/core/link_spec.rb +80 -0
  55. data/spec/atum/core/paginator_spec.rb +72 -0
  56. data/spec/atum/core/request_spec.rb +110 -0
  57. data/spec/atum/core/resource_spec.rb +66 -0
  58. data/spec/atum/core/response_spec.rb +127 -0
  59. data/spec/atum/core/schema/api_schema_spec.rb +49 -0
  60. data/spec/atum/core/schema/link_schema_spec.rb +91 -0
  61. data/spec/atum/core/schema/parameter_choice_spec.rb +40 -0
  62. data/spec/atum/core/schema/parameter_spec.rb +24 -0
  63. data/spec/atum/core/schema/resource_schema_spec.rb +24 -0
  64. data/spec/atum/generation/generator_link_spec.rb +62 -0
  65. data/spec/atum/generation/generator_resource_spec.rb +44 -0
  66. data/spec/atum/generation/generator_service_spec.rb +41 -0
  67. data/spec/atum/generation/generators/base_generator_spec.rb +75 -0
  68. data/spec/atum/generation/generators/client_generator_spec.rb +30 -0
  69. data/spec/atum/generation/generators/module_generator_spec.rb +37 -0
  70. data/spec/atum/generation/generators/resource_generator_spec.rb +46 -0
  71. data/spec/atum/generation/options_parameter_spec.rb +27 -0
  72. data/spec/fixtures/fruity_schema.json +161 -0
  73. data/spec/fixtures/sample_schema.json +139 -0
  74. data/spec/integration/client_integration_spec.rb +91 -0
  75. data/spec/spec_helper.rb +11 -0
  76. metadata +303 -0
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Atum::Core::Resource do
4
+ let(:method_name) { 'known_method' }
5
+ let(:links) { { "#{method_name}" => nil } }
6
+ let(:resource) { described_class.new(links) }
7
+ let(:resource_schema) do
8
+ Atum::Core::Schema::ApiSchema.new(SAMPLE_SCHEMA).resource_schema_for('resource')
9
+ end
10
+
11
+ describe '#respond_to?' do
12
+ subject { resource.respond_to?(method_name) }
13
+
14
+ context 'when a link for the method exists' do
15
+ it { is_expected.to be_truthy }
16
+ end
17
+
18
+ context 'when a link is missing for the method' do
19
+ let(:links) { {} }
20
+ it { is_expected.to be_falsey }
21
+ end
22
+ end
23
+
24
+ describe 'calling a method on the resource' do
25
+ let(:args) { double }
26
+ subject(:method) { -> { resource.send(method_name, args) } }
27
+
28
+ context 'when a link for the method exists' do
29
+ let(:link) { double(run: nil) }
30
+ let(:links) { { "#{method_name}" => link } }
31
+
32
+ it 'should send message :run to the link' do
33
+ expect(link).to receive(:run).with(args)
34
+ method.call
35
+ end
36
+ end
37
+
38
+ context 'when a link is missing for the method' do
39
+ let(:links) { {} }
40
+ it { is_expected.to raise_error(NoMethodError) }
41
+ end
42
+ end
43
+
44
+ # it 'raises on invalid link' do
45
+ # expect { resource.unknown }
46
+ # .to raise_error(NoMethodError,
47
+ # "undefined method `unknown' for #<Atum::Core::Resource")
48
+ # end
49
+
50
+ # context 'when a link is available' do
51
+ # let(:link) do
52
+ # Atum::Core::Link.new('https://username:password@example.com',
53
+ # schema_resource.link_schema('list'))
54
+ # end
55
+ # let(:params) { { 'list' => link } }
56
+ # let(:response_body) { { 'resources' => ['Hello, world!'] } }
57
+
58
+ # it 'gets the link' do
59
+ # stub_request(:get, 'https://username:password@example.com/resource')
60
+ # .to_return(status: 200, body: response_body.to_json,
61
+ # headers: { 'Content-Type' => 'application/json' })
62
+
63
+ # expect(resource.list({})).to eq(['Hello, world!'])
64
+ # end
65
+ # end
66
+ end
@@ -0,0 +1,127 @@
1
+ require 'spec_helper'
2
+
3
+ describe Atum::Core::Response do
4
+ let(:response) { anything }
5
+ let(:api_response) { described_class.new(response) }
6
+
7
+ describe '#body' do
8
+ subject(:body) { api_response.body }
9
+
10
+ context 'when the response is json' do
11
+ let(:response_body) { { name: 'thing', description: 'awesome thing' } }
12
+ let(:response) do
13
+ double(headers: { 'Content-Type' => 'application/json' },
14
+ body: { 'thing' => response_body }.to_json,
15
+ status: 200)
16
+ end
17
+
18
+ it { is_expected.to be_a(Hash) }
19
+ end
20
+
21
+ context 'when the response is not json' do
22
+ let(:response_body) { 'FOOBARBAZ' }
23
+ let(:response) do
24
+ double(headers: { 'Content-Type' => 'application/text' },
25
+ body: 'FOOBARBAZ', status: 200)
26
+ end
27
+
28
+ it 'should come through raw' do
29
+ expect(body).to eq(response_body)
30
+ end
31
+ end
32
+ end
33
+
34
+ describe '#json?' do
35
+ subject { api_response.json? }
36
+
37
+ let(:response) { double(headers: { 'Content-Type' => content_type }) }
38
+
39
+ context 'when the response is json' do
40
+ let(:content_type) { 'application/json' }
41
+ it { is_expected.to be_truthy }
42
+ end
43
+
44
+ context 'when the response is not json' do
45
+ let(:content_type) { 'application/text' }
46
+ it { is_expected.to be_falsey }
47
+ end
48
+ end
49
+
50
+ describe 'error?' do
51
+ subject { api_response.error? }
52
+
53
+ let(:response) { double(status: status) }
54
+
55
+ context 'when the response is an error' do
56
+ let(:status) { 401 }
57
+ it { is_expected.to be_truthy }
58
+ end
59
+
60
+ context 'when the response is not an error' do
61
+ let(:status) { 200 }
62
+ it { is_expected.to be_falsey }
63
+ end
64
+ end
65
+
66
+ shared_examples_for 'it needs the response to be json' do
67
+ context 'when the response is not json' do
68
+ before { allow(api_response).to receive(:json?) { false } }
69
+ it { is_expected.to raise_error(Atum::Core::ResponseError) }
70
+ end
71
+ end
72
+
73
+ describe 'meta' do
74
+ subject(:method) { -> { api_response.meta } }
75
+
76
+ it_behaves_like 'it needs the response to be json'
77
+
78
+ context 'when the response is json' do
79
+ before do
80
+ allow(api_response).to receive(:json?) { true }
81
+ allow(api_response).to receive(:json_body) { body }
82
+ end
83
+ subject { method.call }
84
+ let(:meta) { double }
85
+
86
+ context 'when meta is present' do
87
+ let(:body) { { 'meta' => meta } }
88
+ it { is_expected.to eq(meta) }
89
+ end
90
+
91
+ context 'when meta is not present' do
92
+ let(:body) { {} }
93
+ it { is_expected.to eq({}) }
94
+ end
95
+ end
96
+ end
97
+
98
+ describe 'limit' do
99
+ subject(:method) { -> { api_response.limit } }
100
+
101
+ it_behaves_like 'it needs the response to be json'
102
+
103
+ context 'when the response is json' do
104
+ before do
105
+ allow(api_response).to receive(:json?) { true }
106
+ allow(api_response).to receive(:json_body) { body }
107
+ end
108
+ subject { method.call }
109
+ let(:limit) { double }
110
+
111
+ context 'and limit is present' do
112
+ let(:body) { { 'meta' => { 'limit' => limit } } }
113
+ it { is_expected.to eq(limit) }
114
+ end
115
+
116
+ context 'and limit is not present' do
117
+ let(:body) { { 'meta' => {} } }
118
+ it { is_expected.to eq(nil) }
119
+ end
120
+
121
+ context 'and meta is not present' do
122
+ let(:body) { {} }
123
+ it { is_expected.to eq(nil) }
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Atum::Core::Schema::ApiSchema do
4
+ let(:schema) { described_class.new(SAMPLE_SCHEMA) }
5
+
6
+ describe '#description' do
7
+ it 'returns the schema description' do
8
+ expect(schema.description).to eq(SAMPLE_SCHEMA['description'])
9
+ end
10
+ end
11
+
12
+ describe '#resource_schema_for' do
13
+ it 'has name' do
14
+ expect(schema.resource_schema_for('resource').name).to eq('resource')
15
+ end
16
+
17
+ it 'raises with unknown resources' do
18
+ expect { schema.resource_schema_for('lolno') }
19
+ .to raise_error(Atum::Core::SchemaError)
20
+ end
21
+ end
22
+
23
+ describe '#resource_schemas' do
24
+ it 'has several resource schemas' do
25
+ expect(schema.resource_schemas.map(&:name))
26
+ .to eq(%w(resource another-resource))
27
+ end
28
+ end
29
+
30
+ describe '#inspect' do
31
+ it 'includes description' do
32
+ expect(schema.inspect).to include(SAMPLE_SCHEMA['description'])
33
+ end
34
+ end
35
+
36
+ describe '#lookup_path' do
37
+ it 'returns whole schema for empty path' do
38
+ expect(schema.lookup_path).to eq(SAMPLE_SCHEMA)
39
+ end
40
+
41
+ it 'fetches values at nested keys' do
42
+ expect(schema.lookup_path('definitions', 'another-resource', 'id'))
43
+ .to eq('schema/another-resource')
44
+
45
+ expect(schema.lookup_path('definitions', 'resource'))
46
+ .to eq(SAMPLE_SCHEMA['definitions']['resource'])
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe Atum::Core::Schema::LinkSchema do
4
+ let(:schema) { Atum::Core::Schema::ApiSchema.new(SAMPLE_SCHEMA) }
5
+ let(:resource) { schema.resource_schema_for('resource') }
6
+ let(:list) { resource.link_schema_for('list') }
7
+ let(:info) { resource.link_schema_for('info') }
8
+ let(:identify) { resource.link_schema_for('identify_resource') }
9
+ let(:create) { resource.link_schema_for('create') }
10
+ let(:update) { resource.link_schema_for('update') }
11
+
12
+ describe '#name' do
13
+ it 'returns the name' do
14
+ expect(list.name).to eq('list')
15
+ end
16
+ end
17
+
18
+ describe '#description' do
19
+ it 'returns the link description' do
20
+ expect(list.description).to eq('Show all sample resources')
21
+ end
22
+ end
23
+
24
+ describe '#method' do
25
+ it 'returns the link method' do
26
+ expect(list.method).to eq(:get)
27
+ end
28
+ end
29
+
30
+ describe '#needs_request_body?' do
31
+ subject { link_schema.needs_request_body? }
32
+
33
+ context 'when link_schema has a schema' do
34
+ let(:link_schema) { create }
35
+ it { is_expected.to be_truthy }
36
+ end
37
+
38
+ context "when link_schema doesn't have a schema" do
39
+ let(:link_schema) { list }
40
+ it { is_expected.to be_falsey }
41
+ end
42
+ end
43
+
44
+ describe '#parameters' do
45
+ let(:parameters) { identify.parameters }
46
+
47
+ it 'returns an array of parameters' do
48
+ expect(parameters).to be_an(Array)
49
+ end
50
+
51
+ it 'returns the right number of parameters' do
52
+ expect(parameters.length).to eq(1)
53
+ end
54
+
55
+ it 'gives parameters the right names' do
56
+ expect(parameters.first.name)
57
+ .to eq('resource_uuid_field_or_resource_email_field')
58
+ end
59
+
60
+ it 'gives parameters the right descriptions' do
61
+ expect(parameters.first.description)
62
+ .to eq('A sample UUID field or A sample email address field')
63
+ end
64
+ end
65
+
66
+ describe '#construct_path' do
67
+ subject(:method) { -> { info.construct_path(*args) } }
68
+
69
+ context 'with valid args' do
70
+ let(:args) { ['4472831-bf66-4bc2-865f-e2c4c2b14c78'] }
71
+ it 'prepends a relative url to the action' do
72
+ expect(method.call).to eq('/resource/4472831-bf66-4bc2-865f-e2c4c2b14c78')
73
+ end
74
+ end
75
+
76
+ context 'with missing args' do
77
+ let(:args) { [] }
78
+ it { is_expected.to raise_error(ArgumentError) }
79
+ end
80
+
81
+ context 'with unwanted args' do
82
+ let(:args) { %w(too many args) }
83
+ it { is_expected.to raise_error(ArgumentError) }
84
+ end
85
+
86
+ it 'returns relative url' do
87
+ expect(update.construct_path('4472831-bf66-4bc2-865f-e2c4c2b14c78'))
88
+ .to eq('/resource/4472831-bf66-4bc2-865f-e2c4c2b14c78')
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Atum::Core::Schema::ParameterChoice do
4
+ let(:param_1) { Atum::Core::Schema::Parameter.new('resource', 'id', 'foo') }
5
+ let(:param_2) { Atum::Core::Schema::Parameter.new('resource', 'email', 'bar') }
6
+ let(:param_3) { Atum::Core::Schema::Parameter.new(nil, 'token', 'baz') }
7
+
8
+ let(:parameter_choice) { described_class.new('resource', parameters) }
9
+
10
+ describe '#description' do
11
+ let(:parameters) { [param_1, param_2, param_3] }
12
+ subject { parameter_choice.description }
13
+
14
+ it { is_expected.to eq('foo or bar or baz') }
15
+ end
16
+
17
+ describe '#inspect' do
18
+ let(:parameters) { [param_1, param_2, param_3] }
19
+
20
+ it 'should include each of the parameters' do
21
+ expect(parameter_choice.inspect).to include(param_1.inspect)
22
+ expect(parameter_choice.inspect).to include(param_2.inspect)
23
+ expect(parameter_choice.inspect).to include(param_3.inspect)
24
+ end
25
+ end
26
+
27
+ describe '#name' do
28
+ subject { parameter_choice.name }
29
+
30
+ context 'when both parameters have a resource name' do
31
+ let(:parameters) { [param_1, param_2] }
32
+ it { is_expected.to eq('resource_id_or_resource_email') }
33
+ end
34
+
35
+ context "when a parameter doesn't have a resource name" do
36
+ let(:parameters) { [param_1, param_3] }
37
+ it { is_expected.to eq('resource_id_or_resource_token') }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Atum::Core::Schema::Parameter do
4
+ let(:name) { 'id' }
5
+ let(:description) { 'The ID for the resource Yo!' }
6
+ let(:resource_name) { 'resource' }
7
+ subject(:parameter) { described_class.new(resource_name, name, description) }
8
+
9
+ describe '#name' do
10
+ subject { parameter.name }
11
+ it { is_expected.to eq("#{resource_name}_#{name}") }
12
+ end
13
+
14
+ describe '#description' do
15
+ subject { parameter.description }
16
+ it { is_expected.to eq(description) }
17
+ end
18
+
19
+ describe '#inspect' do
20
+ subject { parameter.inspect }
21
+ it { is_expected.to include("#{resource_name}_#{name}") }
22
+ it { is_expected.to include("#{description}") }
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Atum::Core::Schema::ResourceSchema do
4
+ let(:schema) { Atum::Core::Schema::ApiSchema.new(SAMPLE_SCHEMA) }
5
+ let(:resource) { schema.resource_schema_for('resource') }
6
+
7
+ describe '#link_schema_for' do
8
+ it 'gets a link schema' do
9
+ expect(resource.link_schema_for('list').name).to eq('list')
10
+ end
11
+
12
+ it 'raises with unknown link' do
13
+ expect { resource.link_schema_for('lolno') }
14
+ .to raise_error(Atum::Core::SchemaError)
15
+ end
16
+ end
17
+
18
+ describe '#link_schemas' do
19
+ it 'returns an array of link schemas' do
20
+ expect(resource.link_schemas.map(&:name))
21
+ .to eq(%w(list info identify_resource create update delete))
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe Atum::Generation::GeneratorLink do
4
+ let(:generator_link) { described_class.new(link_schema) }
5
+
6
+ describe '#name' do
7
+ let(:link_schema) { double(name: 'foo') }
8
+ it 'delegates to the link schema' do
9
+ expect(generator_link.name).to eq('foo')
10
+ end
11
+ end
12
+
13
+ describe '#description' do
14
+ let(:link_schema) { double(description: 'a really cool link') }
15
+ it 'delegates to the link schema' do
16
+ expect(generator_link.description).to eq('a really cool link')
17
+ end
18
+ end
19
+
20
+ describe '#parameters' do
21
+ let(:params) { [double] }
22
+ let(:link_schema) { instance_double('LinkSchema', parameters: params) }
23
+
24
+ it 'includes the link schema param details' do
25
+ params.each do |param|
26
+ expect(generator_link.parameters).to include(param)
27
+ end
28
+ end
29
+
30
+ it 'adds an optional parameter' do
31
+ expect(generator_link.parameters.last).to be_an(Atum::Generation::OptionsParameter)
32
+ end
33
+ end
34
+
35
+ describe '#parameter_names_with_defaults' do
36
+ let(:link_schema) { double }
37
+ before do
38
+ allow(generator_link).to receive(:parameters)
39
+ .and_return([double(name: 'first_param'),
40
+ double(name: 'options', default: '{}')])
41
+ end
42
+
43
+ it 'should return the right function signature' do
44
+ expect(generator_link.parameter_names_with_defaults).to eq(
45
+ 'first_param, options = {}')
46
+ end
47
+ end
48
+
49
+ describe '#parameter_names' do
50
+ let(:link_schema) { double }
51
+ before do
52
+ allow(generator_link).to receive(:parameters)
53
+ .and_return([double(name: 'first_param'),
54
+ double(name: 'options', default: '{}')])
55
+ end
56
+
57
+ it 'should return the right signature' do
58
+ expect(generator_link.parameter_names).to eq(
59
+ 'first_param, options')
60
+ end
61
+ end
62
+ end