axel 0.0.1

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 (128) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +21 -0
  3. data/.octopolo.yml +2 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +23 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +271 -0
  11. data/Rakefile +13 -0
  12. data/app/models/axel/api_proxy.rb +86 -0
  13. data/app/models/axel/associations/base.rb +64 -0
  14. data/app/models/axel/associations/belongs_to.rb +43 -0
  15. data/app/models/axel/associations/has_many.rb +29 -0
  16. data/app/models/axel/associations/has_one.rb +30 -0
  17. data/app/models/axel/payload.rb +4 -0
  18. data/app/models/axel/payload/base.rb +107 -0
  19. data/app/models/axel/payload/errors.rb +62 -0
  20. data/app/models/axel/payload/metadata.rb +57 -0
  21. data/app/models/axel/querier.rb +166 -0
  22. data/app/models/axel/router.rb +119 -0
  23. data/app/models/axel/service_resource.rb +4 -0
  24. data/app/models/axel/service_resource/associations.rb +80 -0
  25. data/app/models/axel/service_resource/attributes.rb +23 -0
  26. data/app/models/axel/service_resource/automatic_resource.rb +23 -0
  27. data/app/models/axel/service_resource/base.rb +47 -0
  28. data/app/models/axel/service_resource/builder.rb +40 -0
  29. data/app/models/axel/service_resource/inspects.rb +17 -0
  30. data/app/models/axel/service_resource/payload_parser.rb +46 -0
  31. data/app/models/axel/service_resource/queries.rb +25 -0
  32. data/app/models/axel/service_resource/requesters.rb +49 -0
  33. data/app/models/axel/service_resource/routes.rb +19 -0
  34. data/app/models/axel/service_resource/typhoid_extensions.rb +134 -0
  35. data/app/views/axel/base/empty.json.erb +0 -0
  36. data/app/views/axel/base/empty.xml.builder +0 -0
  37. data/app/views/layouts/axel.json.jbuilder +7 -0
  38. data/app/views/layouts/axel.xml.builder +12 -0
  39. data/axel.gemspec +42 -0
  40. data/lib/axel.rb +56 -0
  41. data/lib/axel/application_extensions.rb +13 -0
  42. data/lib/axel/application_helper.rb +27 -0
  43. data/lib/axel/base_controller.rb +6 -0
  44. data/lib/axel/cascadable_attribute.rb +33 -0
  45. data/lib/axel/configurations/resource.rb +29 -0
  46. data/lib/axel/configurations/service.rb +28 -0
  47. data/lib/axel/configurator.rb +54 -0
  48. data/lib/axel/configurators/services.rb +29 -0
  49. data/lib/axel/controller_base.rb +27 -0
  50. data/lib/axel/controller_helpers.rb +209 -0
  51. data/lib/axel/controller_parameters.rb +32 -0
  52. data/lib/axel/engine.rb +14 -0
  53. data/lib/axel/inspector.rb +91 -0
  54. data/lib/axel/payload/remote_error.rb +14 -0
  55. data/lib/axel/request_options.rb +26 -0
  56. data/lib/axel/uri.rb +47 -0
  57. data/lib/axel/version.rb +3 -0
  58. data/lib/generators/axel/install_generator.rb +16 -0
  59. data/lib/generators/templates/README.md +22 -0
  60. data/lib/generators/templates/axel.rb +81 -0
  61. data/script/rails +5 -0
  62. data/spec/controllers/pages_controller_spec.rb +217 -0
  63. data/spec/dummy/README.rdoc +261 -0
  64. data/spec/dummy/Rakefile +7 -0
  65. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  66. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  67. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  68. data/spec/dummy/app/controllers/pages_controller.rb +6 -0
  69. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  70. data/spec/dummy/app/mailers/.gitkeep +0 -0
  71. data/spec/dummy/app/models/.gitkeep +0 -0
  72. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  73. data/spec/dummy/config.ru +4 -0
  74. data/spec/dummy/config/application.rb +62 -0
  75. data/spec/dummy/config/boot.rb +10 -0
  76. data/spec/dummy/config/database.yml +25 -0
  77. data/spec/dummy/config/environment.rb +5 -0
  78. data/spec/dummy/config/environments/development.rb +37 -0
  79. data/spec/dummy/config/environments/production.rb +67 -0
  80. data/spec/dummy/config/environments/test.rb +37 -0
  81. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  82. data/spec/dummy/config/initializers/inflections.rb +15 -0
  83. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  84. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  85. data/spec/dummy/config/initializers/session_store.rb +8 -0
  86. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  87. data/spec/dummy/config/locales/en.yml +5 -0
  88. data/spec/dummy/config/routes.rb +3 -0
  89. data/spec/dummy/db/development.sqlite3 +0 -0
  90. data/spec/dummy/db/test.sqlite3 +0 -0
  91. data/spec/dummy/lib/assets/.gitkeep +0 -0
  92. data/spec/dummy/log/.gitignore +1 -0
  93. data/spec/dummy/log/.gitkeep +0 -0
  94. data/spec/dummy/public/404.html +26 -0
  95. data/spec/dummy/public/422.html +26 -0
  96. data/spec/dummy/public/500.html +25 -0
  97. data/spec/dummy/public/favicon.ico +0 -0
  98. data/spec/dummy/script/rails +6 -0
  99. data/spec/envelope_integration_check.rb +96 -0
  100. data/spec/helpers/axel/application_helper_spec.rb +31 -0
  101. data/spec/lib/axel/associations/base_spec.rb +28 -0
  102. data/spec/lib/axel/associations/belongs_to_spec.rb +62 -0
  103. data/spec/lib/axel/associations/has_many_spec.rb +23 -0
  104. data/spec/lib/axel/associations/has_one_spec.rb +23 -0
  105. data/spec/lib/axel/configurations/resource_spec.rb +15 -0
  106. data/spec/lib/axel/configurations/service_spec.rb +31 -0
  107. data/spec/lib/axel/configurator_spec.rb +26 -0
  108. data/spec/lib/axel/configurators/services_spec.rb +37 -0
  109. data/spec/lib/axel/controller_base_spec.rb +16 -0
  110. data/spec/lib/axel/controller_parameters_spec.rb +31 -0
  111. data/spec/lib/axel/inspector_spec.rb +45 -0
  112. data/spec/lib/axel/request_options_spec.rb +50 -0
  113. data/spec/lib/axel/uri_spec.rb +42 -0
  114. data/spec/lib/axel_spec.rb +64 -0
  115. data/spec/models/axel/api_proxy_spec.rb +66 -0
  116. data/spec/models/axel/payload/errors_spec.rb +165 -0
  117. data/spec/models/axel/payload/metadata_spec.rb +141 -0
  118. data/spec/models/axel/querier_spec.rb +158 -0
  119. data/spec/models/axel/router_spec.rb +115 -0
  120. data/spec/models/axel/service_resource/base_spec.rb +244 -0
  121. data/spec/models/axel/service_resource/builder_spec.rb +64 -0
  122. data/spec/models/axel/service_resource/payload_parser_spec.rb +60 -0
  123. data/spec/spec_helper.rb +39 -0
  124. data/spec/support/address.rb +5 -0
  125. data/spec/support/persona.rb +15 -0
  126. data/spec/support/user.rb +6 -0
  127. data/spec/views/axel/base/empty_spec.rb +34 -0
  128. metadata +508 -0
@@ -0,0 +1,19 @@
1
+ Axel::Router
2
+ module Axel
3
+ module ServiceResource
4
+ module Routes
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def routes
9
+ @_routes ||= {}.with_indifferent_access
10
+ end
11
+
12
+ def route(route_path, name, options = {})
13
+ new_route = Router.new(self, route_path, name, options)
14
+ routes[new_route.method_name] = new_route.define_route
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,134 @@
1
+ module Axel
2
+ module ServiceResource
3
+ module TyphoidExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ extend Axel::CascadableAttribute
8
+ cascade_attribute :site
9
+ cascade_attribute :path
10
+ cascade_attribute :auto_init_fields
11
+ protected
12
+ attr_writer :attributes
13
+ attr_writer :metadata
14
+ attr_writer :remote_errors
15
+ attr_writer :result
16
+ attr_writer :payload
17
+
18
+ public
19
+ attr_reader :metadata
20
+ attr_reader :remote_errors
21
+ attr_reader :result
22
+ attr_reader :payload
23
+ end
24
+
25
+ def envelope?
26
+ payload.has_key?(:metadata) && payload.has_key?(:result)
27
+ end
28
+
29
+ def default_request_options;end
30
+
31
+ def request_and_load(&block)
32
+ metadata.reset!
33
+ remote_errors.reset!
34
+ super
35
+ end
36
+
37
+ # Makes Typhoid::Resource#success check remote_errors
38
+ def resource_exception
39
+ remote_errors.exception || super
40
+ end
41
+
42
+ def create_request(method = :post)
43
+ object_request method, to_params.to_json
44
+ end
45
+
46
+ def update_request(method = :put)
47
+ object_request method, to_params.to_json
48
+ end
49
+
50
+ def delete_request(method = :delete)
51
+ object_request method
52
+ end
53
+
54
+ def build_typhoid_request(options = {})
55
+ self.class.build_typhoid_request request_uri, options
56
+ end
57
+
58
+ def object_request(method, body = nil)
59
+ bare_options = { method: method }
60
+ bare_options[:body] = body if body
61
+ build_typhoid_request retrieve_default_request_options(bare_options)
62
+ end
63
+
64
+ def load_values(hash = {})
65
+ self.payload, self.result, self.metadata, self.remote_errors = PayloadParser.new(hash).parsed
66
+ merge_result
67
+ self
68
+ end
69
+
70
+ def merge_result
71
+ self.attributes.deep_merge! result
72
+ end
73
+
74
+ def after_build(response, error)
75
+ super
76
+ self.remote_errors.status = response.code
77
+ end
78
+
79
+ def attributes
80
+ @attributes ||= {}.with_indifferent_access
81
+ end
82
+
83
+ def retrieve_default_request_options(options)
84
+ RequestOptions.new(compiled_default_request_options, options).compiled
85
+ end
86
+ private :retrieve_default_request_options
87
+
88
+ def compiled_default_request_options
89
+ (self.class.default_request_options ||{}).merge(default_request_options || {})
90
+ end
91
+ private :compiled_default_request_options
92
+
93
+ module ClassMethods
94
+ def default_request_options;end
95
+
96
+ def manual_request(method, uri, request_options = {})
97
+ Typhoeus::Request.send method, uri, request_options
98
+ end
99
+
100
+ def builder
101
+ ::Axel::ServiceResource::Builder
102
+ end
103
+
104
+ def retrieve_default_request_options(options)
105
+ RequestOptions.new(default_request_options, options).compiled
106
+ end
107
+
108
+ def build_typhoid_request(request_uri = nil, options = {})
109
+ uri = request_uri || self.request_uri
110
+ Typhoid::RequestBuilder.new(self, uri, options)
111
+ end
112
+
113
+ # Manually register base URL, useful if the API Proxy is pointing at the
114
+ # wrong location or doesn't know about the location
115
+ def site(url = nil)
116
+ @site = url if url
117
+ resource ? (@site || resource.base_url) : @site
118
+ end
119
+
120
+ # Manually register a path, useful if the API Proxy is pointing at the
121
+ # wrong location or doesn't know about the location
122
+ def path(path = nil)
123
+ if resource
124
+ resource.path = path if path
125
+ resource.path
126
+ else
127
+ @path = path if path
128
+ @path || resource_name
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
File without changes
File without changes
@@ -0,0 +1,7 @@
1
+ # MultiJson will use Oj, currently noted as being faster
2
+ # than most other Parsers available to Ruby
3
+ json.metadata safe_json_load metadata.to_json
4
+
5
+ json.errors safe_json_load(errors.to_json) if errors.display?
6
+
7
+ json.result safe_json_load yield
@@ -0,0 +1,12 @@
1
+ xml.instruct!
2
+ xml.document do
3
+ xml << metadata.to_xml
4
+
5
+ xml << errors.to_xml
6
+
7
+ xml.result do
8
+ # Hack because rabl doesn't like having root-node-less things rendered
9
+ # Example: users/me.rabl renders with a <hash> wrapped around it
10
+ xml << xml_clean(yield)
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'axel/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "axel"
8
+ gem.version = Axel::VERSION
9
+ gem.authors = ["Jon Phenow"]
10
+ gem.email = ["jon.phenow@sportngin.com"]
11
+ gem.description = %q{Building blocks and general helpers for platform services}
12
+ gem.summary = %q{Consistent controller responses, Resources for querying other services consistently, along with some general app support}
13
+ gem.homepage = "http://github.com/sportngin/axel"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency 'rake', "~> 10.0.3"
21
+ gem.add_development_dependency 'rspec-rails', "~> 2.14"
22
+ gem.add_development_dependency 'rspec-its'
23
+ gem.add_development_dependency 'rspec-collection_matchers'
24
+ gem.add_development_dependency 'pry-rails'
25
+ gem.add_development_dependency 'awesome_print', "~> 1.1.0"
26
+ gem.add_development_dependency 'sqlite3', "~> 1.3.6"
27
+ gem.add_development_dependency 'simplecov', "~> 0.7.1"
28
+
29
+ gem.add_development_dependency 'activerecord', '> 3.0'
30
+ gem.add_development_dependency 'gemfury'
31
+
32
+ gem.add_dependency 'activesupport', "> 3.0"
33
+ gem.add_dependency 'actionpack', "> 3.0", "< 4.2"
34
+ gem.add_dependency 'railties', "> 3.0"
35
+
36
+ gem.add_dependency 'rabl', "~> 0.7.9"
37
+ gem.add_dependency 'jbuilder', ">= 0.9.0"
38
+ gem.add_dependency 'oj', "~> 2.0.0"
39
+ gem.add_dependency 'ffi', ">= 1.0.0"
40
+ gem.add_dependency 'typhoid', "~> 0.0.2"
41
+ gem.add_dependency 'json'
42
+ end
@@ -0,0 +1,56 @@
1
+ require 'rabl'
2
+ require 'jbuilder'
3
+ require 'oj'
4
+ require 'typhoid'
5
+ require "axel/version"
6
+ require 'axel/controller_base'
7
+ require "axel/inspector"
8
+ require "axel/request_options"
9
+ require 'axel/uri'
10
+ require 'axel/controller_parameters'
11
+ require 'axel/cascadable_attribute'
12
+ require 'axel/application_extensions'
13
+ require 'axel/configurator'
14
+ require 'axel/payload/remote_error'
15
+
16
+ module Axel
17
+ NotAuthorized = Class.new(StandardError)
18
+ ForceSSL = Class.new(StandardError)
19
+
20
+ def self.config(&block)
21
+ yield _config
22
+ _config.service_configs.each do |name, configuration|
23
+ unless respond_to? name
24
+ define_singleton_method(name) { configuration }
25
+ end
26
+ end
27
+ end
28
+
29
+ def self.service_configurator
30
+ _config.services
31
+ end
32
+
33
+ def self.services
34
+ _config.service_configs
35
+ end
36
+
37
+ def self.resources
38
+ _config.resources
39
+ end
40
+
41
+ def self.environment
42
+ _config.environment
43
+ end
44
+
45
+ def self.manual_environment_set?
46
+ _config.manual_environment_set?
47
+ end
48
+
49
+ def self._config
50
+ @config ||= Axel::Configurator.new
51
+ end
52
+ end
53
+ require 'axel/application_helper'
54
+ require "axel/engine"
55
+ require 'axel/controller_helpers'
56
+ require 'axel/base_controller'
@@ -0,0 +1,13 @@
1
+ require 'rails/application'
2
+ require 'active_support/concern'
3
+ module Axel
4
+ module ApplicationExtensions
5
+ extend ActiveSupport::Concern
6
+ module ClassMethods
7
+ def productionish?
8
+ !!Rails.env.match(/(production|staging)/)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ Rails::Application.send :include, Axel::ApplicationExtensions
@@ -0,0 +1,27 @@
1
+ module Axel
2
+ module ApplicationHelper
3
+ def page_title
4
+ result = controller_params_to_locale
5
+ result ? " - #{result}" : ""
6
+ end
7
+
8
+ private
9
+
10
+ def controller_params_to_locale
11
+ sections = params[:controller].to_s.split("/").compact.map(&:to_sym)
12
+ action = params[:action].to_s.to_sym
13
+ title = t(:titles)
14
+
15
+ sections.each do |s|
16
+ title = title.send("[]", s) if title.is_a?(Hash)
17
+ end
18
+ if title.is_a? Hash
19
+ title[action]
20
+ elsif title.is_a?(String) && !title.match(/class=\"translation_missing\"/)
21
+ title
22
+ else
23
+ nil
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,6 @@
1
+ require 'axel/controller_helpers'
2
+ module Axel
3
+ class BaseController < ControllerBase.new.configured
4
+ include ControllerHelpers
5
+ end
6
+ end
@@ -0,0 +1,33 @@
1
+ module Axel
2
+ module CascadableAttribute
3
+ def inherited(klass)
4
+ super
5
+ _cascadable_attributes.each do |attribute_name|
6
+ klass.instance_variable_set "@#{attribute_name}", _instance_var_for("@#{attribute_name}")
7
+ end
8
+ end
9
+
10
+ def cascade_attribute(*attribute_names)
11
+ self._cascadable_attributes += attribute_names.map(&:to_s)
12
+ end
13
+
14
+ def _cascadable_attributes
15
+ @_cascadable_attributes ||= ["_cascadable_attributes"]
16
+ end
17
+
18
+ def _cascadable_attributes=(arry)
19
+ @_cascadable_attributes = arry
20
+ end
21
+
22
+ def _instance_var_for(attribute_name)
23
+ attribute = instance_variable_get(attribute_name)
24
+ attribute.clone
25
+ rescue
26
+ begin
27
+ attribute.dup
28
+ rescue
29
+ attribute
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ module Axel
2
+ module Configurations
3
+ class Resource
4
+ attr_reader :name
5
+ attr_reader :service
6
+ attr_accessor :attributes
7
+ attr_writer :path
8
+
9
+ def initialize(name, service, options = {})
10
+ @name = name.to_s.singularize
11
+ @service = service
12
+ @attributes = options[:attributes] || []
13
+ @path = options[:path] # If nil it will try to build URL from name and service
14
+ end
15
+
16
+ def full_url
17
+ URI.join(base_url, path).to_s
18
+ end
19
+
20
+ def base_url
21
+ service.url
22
+ end
23
+
24
+ def path
25
+ @path || name.pluralize
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ require 'axel/configurations/resource'
2
+ module Axel
3
+ module Configurations
4
+ class Service
5
+ attr_reader :name
6
+ attr_writer :url
7
+ attr_reader :resources
8
+
9
+ delegate :manual_environment_set?,
10
+ :environment,
11
+ to: Axel
12
+
13
+ def initialize(name, url)
14
+ @name = name.to_s.singularize
15
+ @resources = {}.with_indifferent_access
16
+ @url = url.to_s
17
+ end
18
+
19
+ def url
20
+ manual_environment_set? ? Uri.new(@url).to(*environment).to_s : @url
21
+ end
22
+
23
+ def add_resource(resource_name, options = {})
24
+ resources[resource_name] = Configurations::Resource.new(resource_name, self, options)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,54 @@
1
+ require 'axel/configurators/services'
2
+ module Axel
3
+ class Configurator
4
+ private
5
+ attr_writer :services
6
+ attr_writer :proxy
7
+ attr_writer :environment
8
+
9
+ public
10
+ attr_reader :services
11
+ attr_reader :proxy
12
+ attr_reader :environment
13
+ attr_writer :uses_rails_api
14
+ attr_reader :proxy_request_options
15
+ attr_accessor :environment_uri_config
16
+
17
+ def initialize
18
+ self.services = Configurators::Services.new
19
+ end
20
+
21
+ def service_configs
22
+ services.services
23
+ end
24
+
25
+ def resources
26
+ services.resources
27
+ end
28
+
29
+ def setup_proxy(url, request_options = {})
30
+ self.proxy = ApiProxy.new url, request_options
31
+ proxy.register!
32
+ end
33
+
34
+ def set_environment(name, stage_number = nil)
35
+ self.environment = [name, stage_number]
36
+ end
37
+
38
+ def manual_environment_set?
39
+ self.environment.present?
40
+ end
41
+
42
+ def add_service(service_name, url)
43
+ services.add_service service_name, url
44
+ end
45
+
46
+ def add_resource(service_name, resource_name, options = {})
47
+ services.add_resource service_name, resource_name, options
48
+ end
49
+
50
+ def uses_rails_api?
51
+ !!@uses_rails_api
52
+ end
53
+ end
54
+ end