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,27 @@
1
+ module Atum
2
+ module Core
3
+ module Schema
4
+ class Parameter
5
+ attr_reader :resource_name
6
+
7
+ def initialize(resource_name, name, description)
8
+ @resource_name = resource_name
9
+ @name = name
10
+ @description = description
11
+ end
12
+
13
+ def name
14
+ [@resource_name, @name].compact.join('_')
15
+ end
16
+
17
+ def description
18
+ @description || ''
19
+ end
20
+
21
+ def inspect
22
+ "Parameter(name=#{name}, description=#{description})"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ module Atum
2
+ module Core
3
+ module Schema
4
+ class ParameterChoice
5
+ attr_reader :resource_name, :parameters
6
+
7
+ def initialize(resource_name, parameters)
8
+ @resource_name = resource_name
9
+ @parameters = parameters
10
+ end
11
+
12
+ def description
13
+ @parameters.map(&:description).join(' or ')
14
+ end
15
+
16
+ def name
17
+ @parameters.map do |parameter|
18
+ if parameter.resource_name
19
+ parameter.name
20
+ else
21
+ "#{@resource_name}_#{parameter.name}"
22
+ end
23
+ end.join('_or_')
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,51 @@
1
+ module Atum
2
+ module Core
3
+ module Schema
4
+ class ResourceSchema
5
+ attr_reader :name
6
+
7
+ # Instantiate a resource schema.
8
+ #
9
+ # @param schema [ApiSchema] The whole document's schema
10
+ # @param name [String] The name of the resource to identify in the schema.
11
+ def initialize(schema, definition, name)
12
+ @schema = schema
13
+ @name = name
14
+ @definition = definition
15
+ end
16
+
17
+ %w(description definitions properties).each do |key|
18
+ define_method(key) { @definition[key] }
19
+ end
20
+
21
+ # Get a schema for a named link.
22
+ #
23
+ # @param name [String] The name of the link.
24
+ # @raise [SchemaError] Raised if an unknown link name is provided.
25
+ def link_schema_for(name)
26
+ link_schema = link_schema_hash[name]
27
+ raise SchemaError, "Unknown link '#{name}'." unless link_schema
28
+ link_schema
29
+ end
30
+
31
+ # The link schema children that are part of this resource schema.
32
+ #
33
+ # @return [Array<LinkSchema>] The link schema children.
34
+ def link_schemas
35
+ link_schema_hash.values
36
+ end
37
+
38
+ private
39
+
40
+ def link_schema_hash
41
+ @link_schema_hash ||= Hash[
42
+ @definition['links'].map do |link|
43
+ [link['title'].downcase.gsub(' ', '_'),
44
+ LinkSchema.new(@schema, self, link)]
45
+ end
46
+ ]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,15 @@
1
+ module Atum
2
+ module Generation
3
+ end
4
+ end
5
+
6
+ require 'atum/generation/errors'
7
+ require 'atum/generation/erb_context'
8
+ require 'atum/generation/options_parameter'
9
+ require 'atum/generation/generator_link'
10
+ require 'atum/generation/generator_resource'
11
+ require 'atum/generation/generator_service'
12
+ require 'atum/generation/generators/base_generator'
13
+ require 'atum/generation/generators/module_generator'
14
+ require 'atum/generation/generators/client_generator'
15
+ require 'atum/generation/generators/resource_generator'
@@ -0,0 +1,17 @@
1
+ module Atum
2
+ module Generation
3
+ class ErbContext < Erubis::Context
4
+ def commentify(comment, tabs)
5
+ starter = (' ' * tabs) + '# '
6
+ max_line_length = 78 - (tabs * 2)
7
+ comment.split("\n")
8
+ .map { |l| l.scan(/.{1,#{max_line_length}}/) }
9
+ .flatten.map { |l| starter + l.strip }.join("\n")
10
+ end
11
+
12
+ def method(name, params)
13
+ "#{name}" + (params.length > 0 ? "(#{params})" : '')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ module Atum
2
+ module Generation
3
+ class GeneratorError < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,39 @@
1
+ module Atum
2
+ module Generation
3
+ class GeneratorLink
4
+ def initialize(link_schema)
5
+ @link_schema = link_schema
6
+ end
7
+
8
+ def name
9
+ @link_schema.name
10
+ end
11
+
12
+ def description
13
+ @link_schema.description
14
+ end
15
+
16
+ def parameters
17
+ @parameters ||= begin
18
+ params = @link_schema.parameters
19
+ params << OptionsParameter.new
20
+ params
21
+ end
22
+ end
23
+
24
+ # The list of parameters to render in generated source code for the method
25
+ # signature for the link.
26
+ def parameter_names_with_defaults
27
+ parameters.map do |param|
28
+ s = param.name
29
+ s += " = #{param.default}" if param.respond_to?(:default)
30
+ s
31
+ end.join(', ')
32
+ end
33
+
34
+ def parameter_names
35
+ parameters.map(&:name).join(', ')
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,31 @@
1
+ module Atum
2
+ module Generation
3
+ class GeneratorResource
4
+ def initialize(resource_schema)
5
+ @resource_schema = resource_schema
6
+ end
7
+
8
+ # The name of the resource, in snake case.
9
+ def name
10
+ @resource_schema.name.gsub('-', '_')
11
+ end
12
+
13
+ # Description of the resource.
14
+ def description
15
+ @resource_schema.description
16
+ end
17
+
18
+ # Links available on this resource.
19
+ def links
20
+ @links ||= @resource_schema.link_schemas.map do |link_schema|
21
+ GeneratorLink.new(link_schema)
22
+ end
23
+ end
24
+
25
+ # The name of the resource class in generated code.
26
+ def class_name
27
+ name.camelcase
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,73 @@
1
+ require 'fileutils'
2
+
3
+ module Atum
4
+ module Generation
5
+ class GeneratorService
6
+ def initialize(module_name, schema_file, url, options)
7
+ @module_name = module_name
8
+ @schema = schema_from_file(schema_file)
9
+ @url = url
10
+ @options = options
11
+ end
12
+
13
+ def generate_files
14
+ generate_namespace_folder
15
+ generated_files.each do |gf|
16
+ File.open("#{gf.path}.rb", 'w') do |f|
17
+ f.write(gf.generator.generate)
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def schema_from_file(file)
25
+ Atum::Core::Schema::ApiSchema.new(JSON.parse(File.read(file)))
26
+ end
27
+
28
+ def generate_namespace_folder
29
+ FileUtils.mkdir_p namespace_path
30
+ FileUtils.mkdir_p File.join(namespace_path, 'resources')
31
+ end
32
+
33
+ def resources
34
+ @schema.resource_schemas.map { |r| GeneratorResource.new(r) }
35
+ end
36
+
37
+ def generated_files
38
+ files = []
39
+
40
+ files << GeneratedFile.new(namespace_path,
41
+ Generators::ModuleGenerator.new(*generator_args))
42
+
43
+ files << GeneratedFile.new(File.join(namespace_path, 'client'),
44
+ Generators::ClientGenerator.new(*generator_args))
45
+
46
+ resources.each do |resource|
47
+ files << GeneratedFile.new(
48
+ File.join(namespace_path, 'resources', resource.name.underscore),
49
+ Generators::ResourceGenerator.new(resource, *generator_args))
50
+ end
51
+
52
+ files
53
+ end
54
+
55
+ def namespace
56
+ @module_name.downcase.underscore
57
+ end
58
+
59
+ def namespace_path
60
+ s = []
61
+ s << @options[:path] if @options.key?(:path)
62
+ s << namespace
63
+ File.join(*s)
64
+ end
65
+
66
+ def generator_args
67
+ [@module_name, @schema, @url, @options]
68
+ end
69
+
70
+ class GeneratedFile < Struct.new(:path, :generator); end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,57 @@
1
+ module Atum
2
+ module Generation
3
+ module Generators
4
+ class BaseGenerator
5
+ TEMPLATE_NAME = nil
6
+
7
+ # Generate a static client that uses Atum under the hood. This is a good
8
+ # option if you want to ship a gem or generate API documentation using Yard.
9
+ #
10
+ # @param module_name [String] The name of the module, as rendered in a Ruby
11
+ # source file, to use for the generated client.
12
+ # @param schema [Schema] The schema instance to generate the client from.
13
+ # @param url [String] The URL for the API service.
14
+ # @param options [Hash] Configuration for links. Possible keys include:
15
+ # - default_headers: Optionally, a set of headers to include in every
16
+ # request made by the client. Default is no custom headers.
17
+ def initialize(module_name, schema, url, options)
18
+ @module_name = module_name
19
+ @schema = schema
20
+ @url = url
21
+ @options = options
22
+ end
23
+
24
+ def context
25
+ ErbContext.new(context_hash.merge(module_name: @module_name))
26
+ end
27
+
28
+ def context_hash
29
+ raise NotImplementedError, 'Subclasses must define context_hash'
30
+ end
31
+
32
+ def template
33
+ @template ||= Erubis::Eruby.new(File.read(template_path))
34
+ end
35
+
36
+ def generate
37
+ template.evaluate(context)
38
+ end
39
+
40
+ def resources
41
+ @schema.resource_schemas.map { |r| GeneratorResource.new(r) }
42
+ end
43
+
44
+ private
45
+
46
+ def template_path
47
+ File.expand_path(File.join(File.dirname(__FILE__), 'views',
48
+ "#{template_name}.erb"))
49
+ end
50
+
51
+ def template_name
52
+ raise NotImplementedError, 'Subclasses must define template_name'
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ module Atum
2
+ module Generation
3
+ module Generators
4
+ class ClientGenerator < BaseGenerator
5
+ def context_hash
6
+ { description: @schema.description,
7
+ resources: resources }
8
+ end
9
+
10
+ def template_name
11
+ 'client'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Atum
2
+ module Generation
3
+ module Generators
4
+ class ModuleGenerator < BaseGenerator
5
+ def context_hash
6
+ { default_headers: @options.fetch(:default_headers, {}),
7
+ schema: JSON.dump(@schema.schema),
8
+ resources: resources }
9
+ end
10
+
11
+ def template_name
12
+ 'module'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ module Atum
2
+ module Generation
3
+ module Generators
4
+ class ResourceGenerator < BaseGenerator
5
+ def initialize(resource, *args)
6
+ super(*args)
7
+ @resource = resource
8
+ end
9
+
10
+ def context_hash
11
+ { description: @resource.description,
12
+ class_name: @resource.class_name,
13
+ links: @resource.links,
14
+ resource_name: @resource.name }
15
+ end
16
+
17
+ def template_name
18
+ 'resource'
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ #
3
+ # WARNING: Do not edit by hand, this file was generated by Atum:
4
+ #
5
+ # https://github.com/gocardless/atum
6
+ #
7
+ require 'atum'
8
+ require 'uri'
9
+
10
+ module <%= @module_name %>
11
+ <%= commentify(@description, 1) %>
12
+ class Client
13
+ def initialize(client)
14
+ @client = client
15
+ end
16
+ <% @resources.each do |resource| %>
17
+
18
+ <%= commentify(resource.description, 2) %>
19
+ #
20
+ <%= commentify("@return [" +resource.class_name + "]", 2) %>
21
+ def <%= resource.name %>
22
+ @<%= resource.name %>_resource ||= <%= resource.class_name %>.new(@client)
23
+ end
24
+ <% end %>
25
+ end
26
+ end