axel 0.0.1

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