alephant-publisher-request 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9cfd32b39a5fcdd4d15d0d24925f861614a57bde
4
+ data.tar.gz: e8fb3770ab80f2bcd4b8e972909c23d03d20b449
5
+ SHA512:
6
+ metadata.gz: e2576063f21c41344fb0b74bbc32192fa7e6585e5f0a58212bff778c215cfad2da400ccf30f1ab36ae2bfb0617ca5c7e9ea580cd2dc0ce8276f63b5dce299332
7
+ data.tar.gz: 33794b02c484149ac16b821b65b026fd199ab3054d2feb7df3c9928ca442e4c01b86923169cb221297a497aa26d7e2a40e8ebc069931bc490d435adc7f881cca
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rspec
19
+ .ruby-version
20
+ /config/*.yaml
21
+ /config/*.yml
22
+ /components
23
+ *.swp
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - "jruby"
4
+ script:
5
+ - bundle exec rake all
6
+ notifications:
7
+ email:
8
+ recipients:
9
+ - stevenmajack@gmail.com
10
+ - mark.mxdc@gmail.com
11
+ on_failure: change
12
+ on_success: never
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in alephant-publishing.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,10 @@
1
+ guard 'rake', :task => 'spec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/.+\.rb$})
4
+ watch('spec/spec_helper.rb')
5
+ watch('spec/fixtures/.+')
6
+ end
7
+
8
+ guard 'rake', :task => 'integration' do
9
+ watch(%r{^spec/integration/.+_spec\.rb$})
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 BBC News
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # Alephant::Publisher::Request
2
+
3
+ Dynamic publishing based on data from an API.
4
+
5
+ [![Build Status](https://travis-ci.org/BBC-News/alephant-publisher-request.png?branch=master)](https://travis-ci.org/BBC-News/alephant-publisher-request) [![Dependency Status](https://gemnasium.com/BBC-News/alephant-publisher-request.png)](https://gemnasium.com/BBC-News/alephant-publisher-request) [![Gem Version](https://badge.fury.io/rb/alephant-publisher-request.png)](http://badge.fury.io/rb/alephant-publisher-request)
6
+
7
+ ## Dependencies
8
+
9
+ - JRuby 1.7.8
10
+
11
+ ## Migrating from [Alephant::Publisher](https://github.com/BBC-News/alephant-publisher)
12
+
13
+ 1. Add the new gem in your Gemfile (`gem 'alephant-publisher-request'`).
14
+ 2. Run `bundle install`.
15
+ 3. Require the new gem in your app (`require 'alephant/publisher/queue'`).
16
+ 4. Note that the namespace has changed from `Alephant::Publisher` to `Alephant::Publisher::Request`.
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ gem 'alephant-publisher-request'
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install alephant-publisher-request
31
+
32
+ ## Setup
33
+
34
+ You need to run the gem as a rack application, and pass it the nessasary dependencies. Below is a simple example of the minimum needed to run the server:
35
+
36
+ ### Folder structure
37
+
38
+ ```bash
39
+ src
40
+ ├── components
41
+ │ ├── my_test_component
42
+ │ │ ├── fixtures
43
+ │ │ │ ├── responsive.json
44
+ │ │ ├── templates
45
+ │ │ │ ├── my_test_component.mustache
46
+ │ │ ├── models
47
+ │ │ │ ├── my_test_component.rb
48
+ │ │ ├── mapper.rb
49
+ ```
50
+
51
+ #### Model example
52
+
53
+ The model must extend either the JSON or HTML base from the [alephant-renderer](https://www.github.com/BBC-News/alephant-renderer) `Alephant::Renderer::Views::Html` or `Alephant::Renderer::Views::Json`.
54
+
55
+ ```ruby
56
+ require 'alephant/renderer/views/html'
57
+
58
+ module SomeNameSpace
59
+ class MyTestComponent Alephant::Renderer::Views::Html
60
+
61
+ def some_method
62
+ @body.some_method
63
+ end
64
+
65
+ end
66
+ end
67
+ ```
68
+
69
+ #### Data mapper
70
+
71
+ When getting data from an API, we use data mappers that give us access to the query string parameters allowing us to construct the correct API path.
72
+
73
+ An example of a mapper for an example component would be:
74
+
75
+ > components/my_test_component/mapper.rb
76
+
77
+ ```ruby
78
+ class MyTestComponentMapper < Alephant::Publisher::Request::DataMapper
79
+ def data
80
+ #we have a variable 'context' available that gives us access to the query string params passed to the request.
81
+ #There's a 'get' method available that is passed the constructed API uri and will return the parsed JSON data.
82
+ get "/some/endpoint/#{context['qs_param']}"
83
+
84
+ end
85
+ end
86
+ ```
87
+
88
+ ### Application
89
+
90
+ > config.ru
91
+
92
+ ```ruby
93
+ require 'lib/application'
94
+ run Application.create
95
+ ```
96
+
97
+ > lib/application.rb
98
+
99
+ ```ruby
100
+ module Application
101
+
102
+ def self.create
103
+ Alephant::Publisher::Request.create(processor, data_mapper_factory)
104
+ end
105
+
106
+ def self.processor
107
+ Alephant::Publisher::Request::Processor.new(base_path)
108
+ end
109
+
110
+ def self.base_path
111
+ File.absolute_path(File.join(File.dirname(__FILE__), '..', 'components'))
112
+ end
113
+
114
+ def self.data_mapper_factory
115
+ Alephant::Publisher::Request::DataMapperFactory.new(connection, base_path)
116
+ end
117
+
118
+ def self.connection
119
+ Faraday.new(:url => 'http://www.some-api-endpoint.com')
120
+ end
121
+
122
+ end
123
+ ```
124
+
125
+ ## Usage
126
+
127
+ The server is a simple rack server, so you just need to run:
128
+
129
+ ```bash
130
+ $: rackup
131
+ ```
132
+
133
+ in the `src` directory where the `config.ru` file is.
134
+
135
+ To view components, use the name (the name of the component in the components folder) and any params in the browser:
136
+
137
+ ```bash
138
+ curl http://localhost:9292/my_test_component?some=param
139
+ ```
140
+
141
+ ## Preview Server
142
+
143
+ `alephant preview`
144
+
145
+ The included preview server allows you to see the html generated by your
146
+ templates, both standalone and in the context of a page.
147
+
148
+ **Standalone**
149
+
150
+ `/component/:id/?:fixture?`
151
+
152
+ ### Full page preview
153
+
154
+ When viewing the component in the context of a page, you'll need to retrieve a
155
+ mustache template to provide the page context.
156
+
157
+ When performing an update a regex is applied to replace the static hostnames in
158
+ the retrieved html.
159
+
160
+ **Environment Variables**
161
+
162
+ ```sh
163
+ STATIC_HOST_REGEX="static.(sandbox.dev|int|test|stage|live).yourapp(i)?.com\/"
164
+ PREVIEW_TEMPLATE_URL="http://yourapp.com/template"
165
+ ```
166
+
167
+ **Example Remote Template**
168
+
169
+ `id` is the component/folder name
170
+
171
+ `template` is the mustache template file name
172
+
173
+ `location_in_page` should be something like (for example) `page_head` (specified within a `preview.mustache` file that the consuming application needs to create).
174
+
175
+ - `http://localhost:4567/component/id/template`
176
+ - `http://localhost:4567/preview/id/template/location_in_page`
177
+
178
+ `alephant update`
179
+
180
+ **In page**
181
+
182
+ `/preview/:id/:region/?:fixture?`
183
+
184
+ ## Contributing
185
+
186
+ 1. [Fork it!](http://github.com/BBC-News/alephant-publisher-request/fork)
187
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
188
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
189
+ 4. Push to the branch (`git push origin my-new-feature`)
190
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+
3
+ require 'rspec/core/rake_task'
4
+ require 'rake/rspec'
5
+ require 'bundler/gem_tasks'
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'alephant/publisher/request/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "alephant-publisher-request"
8
+ spec.version = Alephant::Publisher::Request::VERSION
9
+ spec.authors = ["Integralist"]
10
+ spec.email = ["mark.mcdx@gmail.com"]
11
+ spec.summary = "..."
12
+ spec.description = "..."
13
+ spec.homepage = "https://github.com/BBC-News/alephant-publisher-request"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "rspec-nc"
24
+ spec.add_development_dependency "guard"
25
+ spec.add_development_dependency "guard-rake"
26
+ spec.add_development_dependency "pry"
27
+ spec.add_development_dependency "rack-test"
28
+ spec.add_development_dependency "spurious-ruby-awssdk-helper"
29
+ spec.add_development_dependency "rake-rspec"
30
+
31
+ spec.add_runtime_dependency 'rack'
32
+ spec.add_runtime_dependency 'rake'
33
+ spec.add_runtime_dependency 'faraday'
34
+ spec.add_runtime_dependency 'aws-sdk', '~> 1.0'
35
+ spec.add_runtime_dependency 'mustache', '>= 0.99.5'
36
+ spec.add_runtime_dependency 'alephant-logger'
37
+ spec.add_runtime_dependency 'alephant-renderer'
38
+ end
@@ -0,0 +1,75 @@
1
+ require 'alephant/logger'
2
+ require 'alephant/publisher/request/version'
3
+ require 'alephant/publisher/request/processor'
4
+ require 'rack/request'
5
+ require 'rack/response'
6
+ require 'alephant/publisher/request/error'
7
+
8
+ module Alephant
9
+ module Publisher
10
+ module Request
11
+ include Logger
12
+
13
+ def self.create(processor, data_mapper_factory, opts = {})
14
+ Request.new(processor, data_mapper_factory, opts)
15
+ end
16
+
17
+ class Request
18
+ attr_reader :processor, :data_mapper_factory, :opts
19
+
20
+ DEFAULT_CONTENT_TYPE = { "Content-Type" => "text/html" }
21
+
22
+ def initialize(processor, data_mapper_factory, opts)
23
+ @processor = processor
24
+ @data_mapper_factory = data_mapper_factory
25
+ @opts = opts
26
+ end
27
+
28
+ def call(env)
29
+ req = Rack::Request.new(env)
30
+ response = Rack::Response.new("<h1>Not Found</h1>", 404, DEFAULT_CONTENT_TYPE)
31
+
32
+ case req.path_info
33
+ when /status$/
34
+ response = Rack::Response.new('', 204, DEFAULT_CONTENT_TYPE)
35
+ when /component\/(?<id>[^\/]+)$/
36
+ response = Rack::Response.new(
37
+ template_data($~['id'], req.params),
38
+ 200,
39
+ DEFAULT_CONTENT_TYPE
40
+ )
41
+ end
42
+
43
+ response.finish
44
+ rescue ApiError, ConnectionFailed => e
45
+ error_response(e, 502)
46
+ rescue InvalidComponent => e
47
+ error_response(e, 404)
48
+ rescue Exception => e
49
+ error_response e
50
+ end
51
+
52
+ protected
53
+
54
+ def render_component(component_id, params)
55
+ Rack::Response.new(
56
+ template_data(component_id, params),
57
+ 200,
58
+ { "Content-Type" => "text/html" }
59
+ )
60
+ end
61
+
62
+ def template_data(component_id, params)
63
+ mapper = data_mapper_factory.create(component_id, params)
64
+ processor.consume(mapper.data, component_id)
65
+ end
66
+
67
+ def error_response(e = '', code = 500)
68
+ message = opts.fetch(:debug, false) ? e.message : ''
69
+ Rack::Response.new(message, code, DEFAULT_CONTENT_TYPE).finish
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,35 @@
1
+ require 'json'
2
+
3
+ module Alephant
4
+ module Publisher
5
+ module Request
6
+ class DataMapper
7
+ attr_reader :connection, :context
8
+
9
+ def initialize(connection, context = {})
10
+ @connection = connection
11
+ @context = context
12
+ end
13
+
14
+ def data
15
+ raise NotImplementedError
16
+ end
17
+
18
+ protected
19
+
20
+ def get(uri)
21
+ response = connection.get(uri)
22
+ raise InvalidApiResponse, "Status: #{response.status}" unless response.status == 200
23
+ JSON::parse(response.body, :symbolize_names => true)
24
+ rescue Faraday::ConnectionFailed
25
+ raise ConnectionFailed
26
+ rescue JSON::ParserError
27
+ raise InvalidApiResponse, "JSON parsing error: #{response.body}"
28
+ rescue StandardError => e
29
+ raise ApiError, e.message
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,43 @@
1
+ module Alephant
2
+ module Publisher
3
+ module Request
4
+ class DataMapperFactory
5
+ attr_reader :connection, :base_path
6
+
7
+ def initialize(connection, base_path)
8
+ @connection = connection
9
+ @base_path = base_path
10
+ raise InvalidComponentBasePath, base_path unless File.directory? base_path
11
+ end
12
+
13
+ def create(component_id, context = {})
14
+ require base_path_for component_id
15
+
16
+ klass = mapper_class_for(component_id)
17
+ klass.new(connection, context)
18
+ rescue LoadError
19
+ raise InvalidComponentName, "Invalid component name: #{component_id}"
20
+ rescue NameError
21
+ raise InvalidComponentClassName, "Invalid class name #{klass}"
22
+ rescue
23
+ raise InvalidComponent, "Name: #{component_id}, Class: #{klass}"
24
+ end
25
+
26
+ protected
27
+
28
+ def base_path_for(component_id)
29
+ "#{base_path}/#{component_id}/mapper"
30
+ end
31
+
32
+ def camalize(snake_case)
33
+ "#{snake_case.split('_').collect(&:capitalize).join}"
34
+ end
35
+
36
+ def mapper_class_for(component_id)
37
+ Object.const_get("#{camalize component_id}Mapper")
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ module Alephant
2
+ module Publisher
3
+ module Request
4
+ class Error < StandardError; end
5
+ class ConnectionFailed < Error; end
6
+ class InvalidComponent < Error; end
7
+ class ApiError < Error; end
8
+ class InvalidApiResponse < ApiError; end
9
+ class InvalidComponentBasePath < InvalidComponent; end
10
+ class InvalidComponentName < InvalidComponent; end
11
+ class InvalidComponentClassName < InvalidComponent; end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,34 @@
1
+ require 'alephant/publisher/request/processor/base'
2
+
3
+ module Alephant
4
+ module Publisher
5
+ module Request
6
+ class Processor < BaseProcessor
7
+ attr_reader :base_path
8
+
9
+ def initialize(base_path)
10
+ @base_path = base_path
11
+ end
12
+
13
+ def consume(data, component)
14
+ config = config_for component
15
+ renderer_for(config, data).views[component].render
16
+ end
17
+
18
+ def renderer_for(config, data)
19
+ Alephant::Renderer.create(config, data)
20
+ end
21
+
22
+ protected
23
+
24
+ def config_for(component)
25
+ {
26
+ :renderer_id => component,
27
+ :view_path => base_path
28
+ }
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ module Alephant
2
+ module Publisher
3
+ module Request
4
+ class BaseProcessor
5
+ def consume(data)
6
+ raise NotImplementedError.new("You must implement the #consume(data) method")
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module Alephant
2
+ module Publisher
3
+ module Request
4
+ VERSION = "0.0.2"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Alephant::Publisher::Request::DataMapperFactory do
4
+ let (:connection) { instance_double(Faraday::Connection) }
5
+ let (:base_path) { File.join(File.dirname(__FILE__), 'fixtures', 'components') }
6
+
7
+ subject { described_class.new(connection, base_path) }
8
+
9
+ describe ".create" do
10
+ let (:context) do
11
+ {
12
+ :foo => :bar
13
+ }
14
+ end
15
+
16
+ context "using valid parameters" do
17
+ let (:component_id) { 'foo' }
18
+ let (:expected) { FooMapper }
19
+
20
+ specify { expect(subject.create(component_id, context)).to be_a expected }
21
+ end
22
+
23
+ context "using invalid path" do
24
+ let (:base_path) { File.join(File.dirname(__FILE__), 'non_existent_path') }
25
+ let (:expected_exception) { Alephant::Publisher::Request::InvalidComponentBasePath }
26
+
27
+ specify { expect{ subject.create(component_id, context) }.to raise_error expected_exception }
28
+ end
29
+
30
+ context "using invalid component name" do
31
+ let (:component_id) { 'bar' }
32
+ let (:expected_exception) { Alephant::Publisher::Request::InvalidComponentName }
33
+
34
+ specify { expect{ subject.create(component_id, context) }.to raise_error expected_exception }
35
+ end
36
+
37
+ context "using invalid class name" do
38
+ let (:component_id) { 'invalid' }
39
+ let (:expected_exception) { Alephant::Publisher::Request::InvalidComponentClassName }
40
+
41
+ specify { expect{ subject.create(component_id, context) }.to raise_error expected_exception }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+
3
+ describe FooMapper do
4
+ let (:connection) { instance_double(Faraday::Connection, :get => nil) }
5
+ let (:context) do
6
+ {
7
+ :foo => :bar
8
+ }
9
+ end
10
+
11
+ subject { described_class.new(connection, context) }
12
+
13
+ describe "#data" do
14
+ let (:expected_raw_data) do
15
+ {
16
+ :some => 'data'
17
+ }
18
+ end
19
+ let (:expected_data) { JSON::generate(expected_raw_data, :symbolize_names => true) }
20
+ let (:expected_response) { instance_double(Faraday::Response, :body => expected_data, :status => 200) }
21
+
22
+ context "with a valid endpoint" do
23
+ before(:each) do
24
+ allow(connection).to receive(:get).with("/some/test/endpoint/#{context.values[0]}").and_return(expected_response)
25
+ end
26
+
27
+ specify { expect(subject.data).to eq expected_raw_data }
28
+ end
29
+
30
+ context "invalid hostname" do
31
+ let (:expected_exception) { Alephant::Publisher::Request::ConnectionFailed }
32
+ let (:faraday_exception) { Faraday::ConnectionFailed.new(StandardError) }
33
+
34
+ before(:each) do
35
+ allow(connection).to receive(:get).and_raise(faraday_exception)
36
+ end
37
+
38
+ specify { expect{ subject.data }.to raise_error expected_exception }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,6 @@
1
+ class FooMapper < Alephant::Publisher::Request::DataMapper
2
+
3
+ def data
4
+ get "/some/test/endpoint/#{context[:foo]}"
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ require 'alephant/renderer/views/html'
2
+
3
+ module MyApp
4
+ class Foo < Alephant::Renderer::Views::Html
5
+ def content
6
+ @data[:content]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ {{content}}
@@ -0,0 +1,4 @@
1
+ class SomInvalidNameMapper < Alephant::Publisher::Request::DataMapper
2
+
3
+ def data; end
4
+ end
@@ -0,0 +1,62 @@
1
+ require_relative "./spec_helper"
2
+
3
+ describe Alephant::Publisher::Request do
4
+ include Rack::Test::Methods
5
+ let (:response) { instance_double(Faraday::Response, :status => 200, :body => nil) }
6
+ let (:base_path) { File.join(File.dirname(__FILE__), '..', 'fixtures', 'components') }
7
+ let (:processor) { Alephant::Publisher::Request::Processor.new(base_path) }
8
+ let (:connection) { instance_double(Faraday::Connection, :get => response) }
9
+ let (:data_mapper_factory) { Alephant::Publisher::Request::DataMapperFactory.new(connection, base_path) }
10
+ let (:app) { subject.create(processor, data_mapper_factory, { :debug => true }) }
11
+
12
+ describe "status endpoint (/status)" do
13
+ before(:each) do
14
+ get "/status"
15
+ end
16
+
17
+ context "status code" do
18
+ specify { expect(last_response.status).to eq 204 }
19
+ end
20
+ end
21
+
22
+ describe "component endpoint (/component/{component_id}?foo=bar)" do
23
+ let (:component_id) { "foo" }
24
+
25
+ describe "content" do
26
+
27
+ context "with a valid component id" do
28
+ let (:api_response) { "{\"content\":\"#{component_id}\"}" }
29
+ before(:each) do
30
+ allow(response).to receive(:body).and_return(api_response)
31
+ get "/component/#{component_id}"
32
+ end
33
+
34
+ specify { expect(last_response.body.chomp).to eq component_id }
35
+ end
36
+
37
+ end
38
+
39
+ describe "status code" do
40
+
41
+ context "with an invalid component id" do
42
+ let (:component_id) { "foo_invalid" }
43
+ before(:each) do
44
+ get "/component/#{component_id}"
45
+ end
46
+
47
+ specify { expect(last_response.status).to eq 404 }
48
+ end
49
+
50
+ context "with an invalid API endpoint" do
51
+ let (:expected_exception) { Alephant::Publisher::Request::InvalidApiResponse }
52
+ before(:each) do
53
+ allow(connection).to receive(:get).and_raise expected_exception
54
+ get "/component/#{component_id}"
55
+ end
56
+
57
+ specify { expect(last_response.status).to eq 502 }
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ ENV["RACK_ENV"] = "test"
2
+
3
+ require_relative '../spec_helper'
4
+ require 'spurious/ruby/awssdk/helper'
5
+ require "rack/test"
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ describe Alephant::Publisher::Request::DataMapper do
4
+ let (:context) { { :key => :value } }
5
+ let (:connection) { instance_double(Faraday) }
6
+
7
+ subject { Alephant::Publisher::Request::DataMapper.new(connection, context) }
8
+
9
+ describe ".new" do
10
+ specify { expect(subject).to be_a Alephant::Publisher::Request::DataMapper }
11
+ end
12
+
13
+ describe "#data" do
14
+ context "not overridden" do
15
+ specify { expect { subject.data } .to raise_error NotImplementedError }
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ describe Alephant::Publisher::Request::Processor do
4
+ let (:base_path) { File.join(File.dirname(__FILE__), 'fixtures', 'components') }
5
+ subject { described_class.new(base_path) }
6
+
7
+ describe ".new" do
8
+ specify { expect(subject).to be_a described_class }
9
+ end
10
+
11
+ describe "#consume" do
12
+ let (:data) do
13
+ {
14
+ :content => "Foo Bar"
15
+ }
16
+ end
17
+
18
+ context "using valid data" do
19
+ let (:component) { "foo" }
20
+
21
+ specify { expect(subject.consume(data, component)).to eq "#{data.values.first}\n" }
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ describe Alephant::Publisher::Request do
4
+ let (:processor) { instance_double(Alephant::Publisher::Request::Processor, :consume => nil) }
5
+ let (:data_mapper_factory) { instance_double(Alephant::Publisher::Request::DataMapperFactory, :create => nil) }
6
+
7
+ describe ".create" do
8
+ context "Using valid params" do
9
+ let (:expected) { Alephant::Publisher::Request::Request }
10
+
11
+ specify { expect(subject.create(processor, data_mapper_factory)).to be_a expected }
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,11 @@
1
+ require 'pry'
2
+
3
+ require 'aws-sdk'
4
+ require 'faraday'
5
+ require 'alephant/renderer'
6
+ require 'alephant/publisher/request'
7
+ require 'alephant/publisher/request/error'
8
+ require 'alephant/publisher/request/data_mapper'
9
+ require 'alephant/publisher/request/data_mapper_factory'
10
+
11
+ require_relative './fixtures/components/foo/mapper'
metadata ADDED
@@ -0,0 +1,307 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alephant-publisher-request
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Integralist
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-nc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack-test
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: spurious-ruby-awssdk-helper
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rack
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rake
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: faraday
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: aws-sdk
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ~>
186
+ - !ruby/object:Gem::Version
187
+ version: '1.0'
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ~>
193
+ - !ruby/object:Gem::Version
194
+ version: '1.0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: mustache
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - '>='
200
+ - !ruby/object:Gem::Version
201
+ version: 0.99.5
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - '>='
207
+ - !ruby/object:Gem::Version
208
+ version: 0.99.5
209
+ - !ruby/object:Gem::Dependency
210
+ name: alephant-logger
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - '>='
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :runtime
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - '>='
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: alephant-renderer
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :runtime
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - '>='
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ description: '...'
238
+ email:
239
+ - mark.mcdx@gmail.com
240
+ executables: []
241
+ extensions: []
242
+ extra_rdoc_files: []
243
+ files:
244
+ - .gitignore
245
+ - .travis.yml
246
+ - Gemfile
247
+ - Guardfile
248
+ - LICENSE.txt
249
+ - README.md
250
+ - Rakefile
251
+ - alephant-publisher-request.gemspec
252
+ - lib/alephant/publisher/request.rb
253
+ - lib/alephant/publisher/request/data_mapper.rb
254
+ - lib/alephant/publisher/request/data_mapper_factory.rb
255
+ - lib/alephant/publisher/request/error.rb
256
+ - lib/alephant/publisher/request/processor.rb
257
+ - lib/alephant/publisher/request/processor/base.rb
258
+ - lib/alephant/publisher/request/version.rb
259
+ - spec/data_mapper_factory_spec.rb
260
+ - spec/data_mapper_spec.rb
261
+ - spec/fixtures/components/foo/mapper.rb
262
+ - spec/fixtures/components/foo/models/foo.rb
263
+ - spec/fixtures/components/foo/templates/foo.mustache
264
+ - spec/fixtures/components/invalid/mapper.rb
265
+ - spec/integration/rack_server_spec.rb
266
+ - spec/integration/spec_helper.rb
267
+ - spec/not_implemented_mapper_spec.rb
268
+ - spec/processor_spec.rb
269
+ - spec/request_spec.rb
270
+ - spec/spec_helper.rb
271
+ homepage: https://github.com/BBC-News/alephant-publisher-request
272
+ licenses:
273
+ - MIT
274
+ metadata: {}
275
+ post_install_message:
276
+ rdoc_options: []
277
+ require_paths:
278
+ - lib
279
+ required_ruby_version: !ruby/object:Gem::Requirement
280
+ requirements:
281
+ - - '>='
282
+ - !ruby/object:Gem::Version
283
+ version: '0'
284
+ required_rubygems_version: !ruby/object:Gem::Requirement
285
+ requirements:
286
+ - - '>='
287
+ - !ruby/object:Gem::Version
288
+ version: '0'
289
+ requirements: []
290
+ rubyforge_project:
291
+ rubygems_version: 2.2.2
292
+ signing_key:
293
+ specification_version: 4
294
+ summary: '...'
295
+ test_files:
296
+ - spec/data_mapper_factory_spec.rb
297
+ - spec/data_mapper_spec.rb
298
+ - spec/fixtures/components/foo/mapper.rb
299
+ - spec/fixtures/components/foo/models/foo.rb
300
+ - spec/fixtures/components/foo/templates/foo.mustache
301
+ - spec/fixtures/components/invalid/mapper.rb
302
+ - spec/integration/rack_server_spec.rb
303
+ - spec/integration/spec_helper.rb
304
+ - spec/not_implemented_mapper_spec.rb
305
+ - spec/processor_spec.rb
306
+ - spec/request_spec.rb
307
+ - spec/spec_helper.rb