atum 0.5.0

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