imprenta 0.0.3 → 0.0.4

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 (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