imprenta 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +6 -0
  4. data/README.md +55 -4
  5. data/Rakefile +11 -0
  6. data/imprenta.gemspec +5 -1
  7. data/lib/imprenta/cache_page.rb +8 -17
  8. data/lib/imprenta/configuration.rb +5 -0
  9. data/lib/imprenta/content_rack.rb +27 -0
  10. data/lib/imprenta/content_server/file.rb +36 -0
  11. data/lib/imprenta/content_server/s3.rb +32 -0
  12. data/lib/imprenta/rails.rb +5 -1
  13. data/lib/imprenta/static_server.rb +3 -7
  14. data/lib/imprenta/storage/S3.rb +39 -0
  15. data/lib/imprenta/storage/file.rb +25 -0
  16. data/lib/imprenta/version.rb +1 -1
  17. data/lib/imprenta.rb +7 -3
  18. data/spec/configuration_spec.rb +57 -0
  19. data/spec/dummy/README.rdoc +261 -0
  20. data/spec/dummy/Rakefile +7 -0
  21. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  22. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  23. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  24. data/spec/dummy/app/controllers/home_controller.rb +10 -0
  25. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  26. data/spec/dummy/app/mailers/.gitkeep +0 -0
  27. data/spec/dummy/app/models/.gitkeep +0 -0
  28. data/spec/dummy/app/views/home/dummy.html.erb +1 -0
  29. data/spec/dummy/app/views/home/index.html.erb +1 -0
  30. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  31. data/spec/dummy/config/application.rb +17 -0
  32. data/spec/dummy/config/boot.rb +10 -0
  33. data/spec/dummy/config/database.yml +25 -0
  34. data/spec/dummy/config/environment.rb +5 -0
  35. data/spec/dummy/config/environments/development.rb +12 -0
  36. data/spec/dummy/config/environments/production.rb +12 -0
  37. data/spec/dummy/config/environments/test.rb +12 -0
  38. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  39. data/spec/dummy/config/initializers/inflections.rb +15 -0
  40. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  41. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  42. data/spec/dummy/config/initializers/session_store.rb +8 -0
  43. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  44. data/spec/dummy/config/locales/en.yml +5 -0
  45. data/spec/dummy/config/routes.rb +5 -0
  46. data/spec/dummy/config.ru +4 -0
  47. data/spec/dummy/db/test.sqlite3 +0 -0
  48. data/spec/dummy/lib/assets/.gitkeep +0 -0
  49. data/spec/dummy/log/.gitkeep +0 -0
  50. data/spec/dummy/public/404.html +26 -0
  51. data/spec/dummy/public/422.html +26 -0
  52. data/spec/dummy/public/500.html +25 -0
  53. data/spec/dummy/public/favicon.ico +0 -0
  54. data/spec/dummy/script/rails +6 -0
  55. data/spec/features/publish_spec.rb +26 -0
  56. data/spec/file_storage_spec.rb +25 -0
  57. data/spec/spec_helper.rb +16 -0
  58. data/spec/support/dummy_rack.rb +5 -0
  59. metadata +152 -9
  60. data/lib/imprenta/file_rack.rb +0 -48
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: addc2eedab80a43efb3d54cd43969312be95631e
4
- data.tar.gz: 6e50491dc5a26982441fd9cd7aad02809b65cb83
3
+ metadata.gz: a41c878c7744c585924be4102d5f1bd9a8139dfc
4
+ data.tar.gz: 1be6f4b0bbba656894081372eae2cd0b3e134806
5
5
  SHA512:
6
- metadata.gz: 9d1f1d4b162d4c010c46d98d3686a4eb7dc43775c2afff88b9ee2f4aace1e4af12178a637560de7ee7132c39969eca159ce1da33bb00465d9f182d293f19c769
7
- data.tar.gz: 40b4b6e2f02600ac8844ea01c1302bbb511f1d10e8bd6e4914f5cc3401613157bac2b4866d586fa9938b5a7f03deb549d563a4c515a921587fa5eab3af5140d6
6
+ metadata.gz: 27c87f0c08066a52c5367fe2d37d8f37bfc255d3d1cb006136d1a79677af5499a483263a1e0b67cd03acd591d78be702982c262d4b9d116621e5d5b0db2cd2bf
7
+ data.tar.gz: bbf9c4a5bfe0863f80b19905585900d4ccbe49694dce25ce288e35518f84b3e244e162860d4d81e4f592b28ae62675adb8b9977a48d486bb616681fc73b3d7b3
data/.gitignore CHANGED
@@ -12,6 +12,7 @@ lib/bundler/man
12
12
  pkg
13
13
  rdoc
14
14
  spec/reports
15
+ spec/dummy/log
15
16
  test/tmp
16
17
  test/version_tmp
17
18
  tmp
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ script: "bundle exec rake"
3
+ rvm:
4
+ - 2.0.0
5
+ gemfile:
6
+ - Gemfile
data/README.md CHANGED
@@ -1,8 +1,11 @@
1
- # Imprenta
1
+ [![Build Status](https://api.travis-ci.org/skyscrpr/imprenta.png?branch=master)](http://travis-ci.org/skyscrpr/imprenta)
2
+ [![Code Climate](https://codeclimate.com/repos/5272d3faf3ea004b9c013f64/badges/53c51fa28cabe58bf214/gpa.png)](https://codeclimate.com/repos/5272d3faf3ea004b9c013f64/feed)
3
+
4
+ # Imprenta - Publish and Serve Static Pages within Rails.
2
5
 
3
6
  The goal of this gem is to provide an easy and efficient way to generate and serve
4
7
  static pages within Rails. The perfect use case for this gem is when your users
5
- generate some content that gets published and then it barely changes. e.g: a blog post,
8
+ generate some content that gets published and after this it almost never change. e.g: a blog post,
6
9
  landing page, about.me, etc.
7
10
 
8
11
  The gem will provide with methods to save generated templates as static html pages.
@@ -36,8 +39,6 @@ def publish
36
39
  redirect_to root_path, success: 'Yei page published!'
37
40
  end
38
41
  ```
39
-
40
-
41
42
 
42
43
  Then in your routes add the following:
43
44
 
@@ -45,8 +46,16 @@ Then in your routes add the following:
45
46
  get 'mystatic-pages/:id', :to => Imprenta.server
46
47
  ```
47
48
 
49
+ Now if you go to your server to following url:
50
+ ```code
51
+ http://localhost:3000/mystatic-pages/mytemplateid
52
+ ```
53
+
54
+ You should be able to see the page you cached in the publish action.
48
55
  ## Configuration
49
56
 
57
+ ### Middlewares
58
+
50
59
  Imprenta allows you to customize the Rack Server (Imprenta.server) with your own middlewares. By defaut, it
51
60
  will have loaded a middleware to handle 500,400,401,404, etc.
52
61
 
@@ -56,6 +65,48 @@ Imprenta.configure do |config|
56
65
  end
57
66
  ```
58
67
 
68
+ ### Storage
69
+
70
+ Imprenta provides two kinds of storage to save the static pages: File and S3. The default one is file.
71
+ If you want to use s3. You can configure the gem the following way:
72
+
73
+
74
+ ```ruby
75
+ Imprenta.configure do |config|
76
+ config.storage :s3
77
+ config.aws_bucket = "bucket"
78
+ config.aws_access_key_id = "xxxxid"
79
+ config.aws_secret_access_key = "xxxkey"
80
+ end
81
+ ```
82
+
83
+ When using s3, it is strongly advisable to use it in conjunction with a reverse proxy (Varnish, Squid).
84
+ Otherwise, it will be hitting s3 for every request. In rails you could use rack-cache and memcached with
85
+ a configuration like this:
86
+
87
+ In your Gemfile:
88
+
89
+ ```ruby
90
+ gem 'rack-cache'
91
+ gem 'dalli'
92
+ ```
93
+
94
+ Then, in your initializer:
95
+
96
+ ```ruby
97
+ Imprenta.configure do |config|
98
+
99
+ client = Dalli::Client.new('localhost:11211',
100
+ :value_max_bytes => 10485760)
101
+
102
+ config.middlewares.use Rack::Cache,
103
+ verbose: true,
104
+ metastore: client,
105
+ entitystore: client,
106
+ end
107
+ ```
108
+
109
+
59
110
  ## Contributing
60
111
 
61
112
  1. Fork it
data/Rakefile CHANGED
@@ -1 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
1
7
  require "bundler/gem_tasks"
8
+ require 'rspec/core/rake_task'
9
+ RSpec::Core::RakeTask.new(:spec)
10
+
11
+ task :default => :spec
12
+ task :test => :spec
data/imprenta.gemspec CHANGED
@@ -18,7 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "rails", "~> 4.0.0"
22
+ spec.add_dependency "fog"
21
23
  spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rails", "~> 4.0.0"
24
+ spec.add_development_dependency "sqlite3"
25
+ spec.add_development_dependency "rspec-rails"
26
+ spec.add_development_dependency "capybara"
23
27
  spec.add_development_dependency "rake"
24
28
  end
@@ -1,32 +1,23 @@
1
1
  module Imprenta
2
2
  module CachePage
3
- # This methods come from action_pack/cache_page'
4
- # https://github.com/rails/actionpack-page_caching
5
- # We didn't need the whole gem. So I decided to get
6
- # just what we need :)
3
+
7
4
  def imprenta_cache_template(args = {})
8
5
  template = args.fetch(:template)
9
6
  layout = args.fetch(:layout) { 'application'}
10
7
  id = args.fetch(:id)
11
8
 
12
9
  content = render_to_string(template: template, layout: layout)
13
- imprenta_cache_page(content, id)
14
- end
15
-
16
- def imprenta_cache_page(content, id, extension = '.html', gzip = Zlib::BEST_COMPRESSION)
17
- path = path_for_id(id, extension)
18
- FileUtils.makedirs(File.dirname(path))
19
- File.open(path, 'wb+') { |f| f.write(content) }
20
- if gzip
21
- Zlib::GzipWriter.open(path + '.gz', gzip) { |f| f.write(content) }
22
- end
10
+ storage.persist(content, id)
23
11
  end
24
12
 
25
13
  private
26
14
 
27
- def path_for_id(id, extension = nil)
28
- page_cache_directory = Rails.public_path
29
- page_cache_directory.to_s + '/imprenta/' + id + extension
15
+ def storage
16
+ @storage ||= case Imprenta.configuration.storage
17
+ when :file then Imprenta::Storage::File.new
18
+ when :s3 then Imprenta::Storage::S3.new
19
+ else raise StandardError.exception("Invalid storage provider")
20
+ end
30
21
  end
31
22
  end
32
23
  end
@@ -3,7 +3,11 @@ module Imprenta
3
3
  # Same configuration pattern that sferik uses in:
4
4
  # https://github.com/sferik/mtgox/blob/master/lib/mtgox/configuration.rb
5
5
  VALID_OPTIONS_KEYS = [:middlewares,
6
+ :storage,
6
7
  :custom_domain,
8
+ :aws_access_key_id,
9
+ :aws_secret_access_key,
10
+ :aws_bucket,
7
11
  :development]
8
12
 
9
13
  attr_accessor *VALID_OPTIONS_KEYS
@@ -20,6 +24,7 @@ module Imprenta
20
24
  def reset
21
25
  self.middlewares = ActionDispatch::MiddlewareStack.new
22
26
  self.development = false
27
+ self.storage = :file
23
28
  self.custom_domain = false
24
29
  end
25
30
 
@@ -0,0 +1,27 @@
1
+ module Imprenta
2
+ class ContentRack
3
+ attr_accessor :custom_domain, :content_server
4
+
5
+ def initialize
6
+ @custom_domain = Imprenta.configuration.custom_domain
7
+ @content_server = case Imprenta.configuration.storage
8
+ when :file then Imprenta::ContentServer::File.new
9
+ when :s3 then Imprenta::ContentServer::S3.new
10
+ else raise StandardError.exception("Invalid storage provider")
11
+ end
12
+ end
13
+
14
+ def call(env)
15
+ path = custom_domain ? env["SERVER_NAME"] : id_from_env(env)
16
+ raise ::ActionController::RoutingError.exception("Page Not Found") unless path
17
+
18
+ content_server.generate_response(path, env)
19
+ end
20
+
21
+ private
22
+
23
+ def id_from_env(env)
24
+ env["action_dispatch.request.path_parameters"][:id]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ module Imprenta
2
+ module ContentServer
3
+ class File
4
+ def generate_response(path, env)
5
+ request = ::Rack::Request.new(env)
6
+ file, headers = pick_file_and_headers_for_path(path, request)
7
+ env.merge!("PATH_INFO" => "/")
8
+ ::Rack::File.new(file, headers).call(env)
9
+ end
10
+
11
+ private
12
+
13
+ def headers
14
+ @headers ||= {'Content-Type' => 'text/html' }
15
+ end
16
+
17
+ def pick_file_and_headers_for_path(path, request)
18
+ encoding = get_best_encoding(request)
19
+ file = "#{Rails.public_path}/imprenta/" + path + '.html'
20
+ if ::File.exist?(file)
21
+ if encoding == 'gzip'
22
+ file = file + '.gz'
23
+ headers['Content-Encoding'] = 'gzip'
24
+ end
25
+ else
26
+ raise ::ActionController::RoutingError.exception("Page Not Found")
27
+ end
28
+ [file, headers]
29
+ end
30
+
31
+ def get_best_encoding(request)
32
+ ::Rack::Utils.select_best_encoding(%w(gzip identity), request.accept_encoding)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ require 'open-uri'
2
+ module Imprenta
3
+ module ContentServer
4
+ class S3
5
+
6
+ attr_accessor :bucket
7
+
8
+ def initialize
9
+ @bucket = Imprenta.configuration.aws_bucket
10
+ end
11
+
12
+ def generate_response(path, env)
13
+ content = open("https://s3.amazonaws.com/#{bucket}/#{path}.html.gz")
14
+ if success?(content)
15
+ body = content.read
16
+ content.close
17
+ headers = content.meta.slice("etag", "last-modified", "content-type")
18
+ headers['Cache-Control'] = 'max-age=3600'
19
+ [200, headers, [body]]
20
+ else
21
+ raise ::ActionController::RoutingError.exception("Page Not Found")
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def success?(content)
28
+ content.status[0] == "200"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1 +1,5 @@
1
- ActionController::Base.send :include, Imprenta::CachePage
1
+ class Engine < Rails::Engine
2
+ initializer 'imprenta.controller_methods' do |app|
3
+ ActionController::Base.send :include, Imprenta::CachePage
4
+ end
5
+ end
@@ -1,11 +1,8 @@
1
1
  module Imprenta
2
2
  class StaticServer
3
3
 
4
- attr_accessor :custom_domain
5
-
6
- def initialize(args = {})
7
- @middleware_stack = args.fetch(:middlewares)
8
- @custom_domain = args[:custom_domain]
4
+ def initialize
5
+ @middleware_stack = Imprenta.configuration.middlewares
9
6
  end
10
7
 
11
8
  def call(env)
@@ -16,8 +13,7 @@ module Imprenta
16
13
  private
17
14
 
18
15
  def build_app
19
- @app ||= @middleware_stack.build(Imprenta::FileRack.new(custom_domain: custom_domain))
16
+ @app ||= @middleware_stack.build(Imprenta::ContentRack.new)
20
17
  end
21
-
22
18
  end
23
19
  end
@@ -0,0 +1,39 @@
1
+ module Imprenta
2
+ module Storage
3
+ class S3
4
+
5
+ attr_accessor :connection, :bucket
6
+
7
+ def initialize
8
+ @bucket = Imprenta.configuration.aws_bucket
9
+ @connection = Fog::Storage.new(provider: 'AWS',
10
+ aws_access_key_id: Imprenta.configuration.aws_access_key_id,
11
+ aws_secret_access_key: Imprenta.configuration.aws_secret_access_key)
12
+ end
13
+
14
+ def persist(content, id, extension = '.html', gzip = Zlib::BEST_COMPRESSION)
15
+ file_name = id + extension
16
+ write_body_to_s3(file_name, content)
17
+ if gzip
18
+ str = StringIO.new()
19
+ gz = Zlib::GzipWriter.new(str, gzip)
20
+ gz.write(content)
21
+ gz.close
22
+ write_body_to_s3(file_name + ".gz", str.string, 'gzip')
23
+ end
24
+ end
25
+
26
+ def write_body_to_s3(key, body, encoding = nil)
27
+ directory.files.create(key: key,
28
+ body: body,
29
+ content_type: 'text/html',
30
+ content_encoding: encoding,
31
+ public: true)
32
+ end
33
+
34
+ def directory
35
+ @directory ||= connection.directories.create(key: bucket, public: true)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ module Imprenta
2
+ module Storage
3
+ class File
4
+ # This methods come from action_pack/cache_page'
5
+ # https://github.com/rails/actionpack-page_caching
6
+ # We didn't need the whole gem. So I decided to get
7
+ # just what we need :)
8
+ def persist(content, id, extension = '.html', gzip = Zlib::BEST_COMPRESSION)
9
+ path = path_for_id(id, extension)
10
+ FileUtils.makedirs(::File.dirname(path))
11
+ ::File.open(path, 'wb+') { |f| f.write(content) }
12
+ if gzip
13
+ Zlib::GzipWriter.open(path + '.gz', gzip) { |f| f.write(content) }
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def path_for_id(id, extension = nil)
20
+ page_cache_directory = Rails.public_path
21
+ page_cache_directory.to_s + '/imprenta/' + id + extension
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module Imprenta
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/imprenta.rb CHANGED
@@ -1,8 +1,13 @@
1
1
  require "imprenta/version"
2
2
  require "rails"
3
+ require "fog"
3
4
  require "imprenta/configuration"
4
- require "imprenta/file_rack"
5
+ require "imprenta/storage/file"
6
+ require "imprenta/storage/S3"
5
7
  require "imprenta/cache_page"
8
+ require "imprenta/content_server/file"
9
+ require "imprenta/content_server/s3"
10
+ require "imprenta/content_rack"
6
11
  require "imprenta/static_server"
7
12
  require "imprenta/rails"
8
13
 
@@ -10,8 +15,7 @@ module Imprenta
10
15
  class << self
11
16
 
12
17
  def server
13
- Imprenta::StaticServer.new(middlewares: configuration.middlewares,
14
- custom_domain: configuration.custom_domain)
18
+ Imprenta::StaticServer.new
15
19
  end
16
20
 
17
21
  def configuration
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Imprenta configuraion" do
4
+ before do
5
+ Imprenta.configuration.reset
6
+ end
7
+
8
+ context "defaults" do
9
+ it "custom_domain is set to false" do
10
+ expect(Imprenta.configuration.custom_domain).to be_false
11
+ end
12
+
13
+ it "storage is set to false" do
14
+ expect(Imprenta.configuration.storage).to eq(:file)
15
+ end
16
+
17
+ it "development is set to false" do
18
+ expect(Imprenta.configuration.development).to be_false
19
+ end
20
+
21
+ it "middlewares is initialized to a middleware stack" do
22
+ expect(Imprenta.configuration.middlewares).to be_kind_of(ActionDispatch::MiddlewareStack)
23
+ end
24
+ end
25
+
26
+ context "when configuring" do
27
+ context "fog" do
28
+ it "sets aws_secret_access_key " do
29
+ Imprenta.configure do |config|
30
+ config.aws_secret_access_key = "xxxsecret"
31
+ end
32
+ expect(Imprenta.configuration.aws_secret_access_key).to eq("xxxsecret")
33
+ end
34
+
35
+ it "aws_access_key_id" do
36
+ Imprenta.configure do |config|
37
+ config.aws_access_key_id = "xxxkeyid"
38
+ end
39
+ expect(Imprenta.configuration.aws_access_key_id).to eq("xxxkeyid")
40
+ end
41
+ end
42
+
43
+ it "allows to set custom_domain to true" do
44
+ Imprenta.configure do |config|
45
+ config.custom_domain = true
46
+ end
47
+ expect(Imprenta.configuration.custom_domain).to be_true
48
+ end
49
+
50
+ it "allows to add custom racks to the config" do
51
+ Imprenta.configure do |config|
52
+ config.middlewares.use DummyRack
53
+ end
54
+ expect(Imprenta.configuration.middlewares.last).to eq(DummyRack)
55
+ end
56
+ end
57
+ end