sinatra-contrib 1.3.0

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 (79) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +135 -0
  3. data/Rakefile +75 -0
  4. data/ideas.md +29 -0
  5. data/lib/sinatra/capture.rb +42 -0
  6. data/lib/sinatra/config_file.rb +151 -0
  7. data/lib/sinatra/content_for.rb +111 -0
  8. data/lib/sinatra/contrib.rb +39 -0
  9. data/lib/sinatra/contrib/all.rb +2 -0
  10. data/lib/sinatra/contrib/setup.rb +53 -0
  11. data/lib/sinatra/contrib/version.rb +45 -0
  12. data/lib/sinatra/cookies.rb +331 -0
  13. data/lib/sinatra/decompile.rb +113 -0
  14. data/lib/sinatra/engine_tracking.rb +96 -0
  15. data/lib/sinatra/extension.rb +95 -0
  16. data/lib/sinatra/json.rb +134 -0
  17. data/lib/sinatra/link_header.rb +132 -0
  18. data/lib/sinatra/multi_route.rb +81 -0
  19. data/lib/sinatra/namespace.rb +282 -0
  20. data/lib/sinatra/reloader.rb +384 -0
  21. data/lib/sinatra/respond_with.rb +245 -0
  22. data/lib/sinatra/streaming.rb +267 -0
  23. data/lib/sinatra/test_helpers.rb +87 -0
  24. data/sinatra-contrib.gemspec +125 -0
  25. data/spec/capture_spec.rb +80 -0
  26. data/spec/config_file/key_value.yml +6 -0
  27. data/spec/config_file/missing_env.yml +4 -0
  28. data/spec/config_file/with_envs.yml +7 -0
  29. data/spec/config_file/with_nested_envs.yml +11 -0
  30. data/spec/config_file_spec.rb +44 -0
  31. data/spec/content_for/different_key.erb +1 -0
  32. data/spec/content_for/different_key.erubis +1 -0
  33. data/spec/content_for/different_key.haml +2 -0
  34. data/spec/content_for/different_key.slim +2 -0
  35. data/spec/content_for/layout.erb +1 -0
  36. data/spec/content_for/layout.erubis +1 -0
  37. data/spec/content_for/layout.haml +1 -0
  38. data/spec/content_for/layout.slim +1 -0
  39. data/spec/content_for/multiple_blocks.erb +4 -0
  40. data/spec/content_for/multiple_blocks.erubis +4 -0
  41. data/spec/content_for/multiple_blocks.haml +8 -0
  42. data/spec/content_for/multiple_blocks.slim +8 -0
  43. data/spec/content_for/multiple_yields.erb +3 -0
  44. data/spec/content_for/multiple_yields.erubis +3 -0
  45. data/spec/content_for/multiple_yields.haml +3 -0
  46. data/spec/content_for/multiple_yields.slim +3 -0
  47. data/spec/content_for/passes_values.erb +1 -0
  48. data/spec/content_for/passes_values.erubis +1 -0
  49. data/spec/content_for/passes_values.haml +1 -0
  50. data/spec/content_for/passes_values.slim +1 -0
  51. data/spec/content_for/same_key.erb +1 -0
  52. data/spec/content_for/same_key.erubis +1 -0
  53. data/spec/content_for/same_key.haml +2 -0
  54. data/spec/content_for/same_key.slim +2 -0
  55. data/spec/content_for/takes_values.erb +1 -0
  56. data/spec/content_for/takes_values.erubis +1 -0
  57. data/spec/content_for/takes_values.haml +3 -0
  58. data/spec/content_for/takes_values.slim +3 -0
  59. data/spec/content_for_spec.rb +201 -0
  60. data/spec/cookies_spec.rb +782 -0
  61. data/spec/decompile_spec.rb +44 -0
  62. data/spec/extension_spec.rb +33 -0
  63. data/spec/json_spec.rb +115 -0
  64. data/spec/link_header_spec.rb +100 -0
  65. data/spec/multi_route_spec.rb +45 -0
  66. data/spec/namespace/foo.erb +1 -0
  67. data/spec/namespace/nested/foo.erb +1 -0
  68. data/spec/namespace_spec.rb +623 -0
  69. data/spec/okjson.rb +581 -0
  70. data/spec/reloader/app.rb.erb +40 -0
  71. data/spec/reloader_spec.rb +441 -0
  72. data/spec/respond_with/bar.erb +1 -0
  73. data/spec/respond_with/bar.json.erb +1 -0
  74. data/spec/respond_with/foo.html.erb +1 -0
  75. data/spec/respond_with/not_html.sass +2 -0
  76. data/spec/respond_with_spec.rb +289 -0
  77. data/spec/spec_helper.rb +6 -0
  78. data/spec/streaming_spec.rb +436 -0
  79. metadata +256 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008-2011 Nicolas Sanguinetti, entp.com, Konstantin Haase
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,135 @@
1
+ Collection of common Sinatra extensions, semi-officially supported.
2
+
3
+ # Goals
4
+
5
+ * For every future Sinatra release, have at least one fully compatible release
6
+ * High code quality, high test coverage
7
+ * Include plugins people usually ask for a lot
8
+
9
+ # TODO
10
+
11
+ * Write documentation, integrate into Sinatra website
12
+ * Finish imports and rewrites
13
+ * Wrap up first release
14
+ * Find contributors (both code and docs)
15
+
16
+ # Included extensions
17
+
18
+ ## Common Extensions
19
+
20
+ These are common extension which will not add significant overhead or change any
21
+ behavior of already existing APIs. They do not add any dependencies not already
22
+ installed with this gem.
23
+
24
+ Currently included:
25
+
26
+ * `sinatra/capture`: Let's you capture the content of blocks in templates.
27
+
28
+ * `sinatra/config_file`: Allows loading configuration from yaml files.
29
+
30
+ * `sinatra/content_for`: Adds Rails-style `content_for` helpers to Haml, Erb,
31
+ Erubis and Slim.
32
+
33
+ * `sinatra/cookies`: A `cookies` helper for reading and writing cookies.
34
+
35
+ * `sinatra/engine_tracking`: Adds methods like `haml?` that allow helper
36
+ methods to check whether they are called from within a template.
37
+
38
+ * `sinatra/json`: Adds a `#json` helper method to return JSON documents.
39
+
40
+ * `sinatra/link_header`: Helpers for generating `link` HTML tags and
41
+ corresponding `Link` HTTP headers. Adds `link`, `stylesheet` and `prefetch`
42
+ helper methods.
43
+
44
+ * `sinatra/multi_route`: Adds ability to define one route block for multiple
45
+ routes and multiple or custom HTTP verbs.
46
+
47
+ * `sinatra/namespace`: Adds namespace support to Sinatra.
48
+
49
+ * `sinatra/respond_with`: Choose action and/or template depending automatically
50
+ depending on the incoming request. Adds helpers `respond_to` and
51
+ `respond_with`.
52
+
53
+
54
+ ## Custom Extensions
55
+
56
+ These extensions may add additional dependencies and enhance the behavior of the
57
+ existing APIs.
58
+
59
+ Currently included:
60
+
61
+ * `sinatra/decompile`: Recreates path patterns from Sinatra's internal data
62
+ structures (used by other extensions).
63
+
64
+ * `sinatra/reloader`: Automatically reloads Ruby files on code changes.
65
+
66
+ ## Other Tools
67
+
68
+ * `sinatra/extension`: Mixin for writing your own Sinatra extensions.
69
+
70
+ * `sinatra/test_helpers`: Helper methods to ease testing your Sinatra
71
+ application. Partly extracted from Sinatra. Testing framework agnostic
72
+
73
+ # Usage
74
+
75
+ ## Classic Style
76
+
77
+ A single extension (example: sinatra-content-for):
78
+
79
+ ``` ruby
80
+ require 'sinatra'
81
+ require 'sinatra/content_for'
82
+ ```
83
+
84
+ Common extensions:
85
+
86
+ ``` ruby
87
+ require 'sinatra'
88
+ require 'sinatra/contrib'
89
+ ```
90
+
91
+ All extensions:
92
+
93
+ ``` ruby
94
+ require 'sinatra'
95
+ require 'sinatra/contrib/all'
96
+ ```
97
+
98
+ ## Modular Style
99
+
100
+ A single extension (example: sinatra-content-for):
101
+
102
+ ``` ruby
103
+ require 'sinatra/base'
104
+ require 'sinatra/content_for'
105
+ require 'sinatra/namespace'
106
+
107
+ class MyApp < Sinatra::Base
108
+ # Note: Some modules are extensions, some helpers, see the specific
109
+ # documentation or the source
110
+ helpers Sinatra::ContentFor
111
+ register Sinatra::Namespace
112
+ end
113
+ ```
114
+
115
+ Common extensions:
116
+
117
+ ``` ruby
118
+ require 'sinatra/base'
119
+ require 'sinatra/contrib'
120
+
121
+ class MyApp < Sinatra::Base
122
+ register Sinatra::Contrib
123
+ end
124
+ ```
125
+
126
+ All extensions:
127
+
128
+ ``` ruby
129
+ require 'sinatra/base'
130
+ require 'sinatra/contrib'
131
+
132
+ class MyApp < Sinatra::Base
133
+ register Sinatra::Contrib
134
+ end
135
+ ```
data/Rakefile ADDED
@@ -0,0 +1,75 @@
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
2
+ require 'open-uri'
3
+ require 'yaml'
4
+ require 'sinatra/contrib/version'
5
+
6
+ desc "run specs"
7
+ task(:spec) { ruby '-S rspec spec -c' }
8
+ task(:test => :spec)
9
+ task(:default => :spec)
10
+
11
+ namespace :doc do
12
+ task :readmes do
13
+ Dir.glob 'lib/sinatra/*.rb' do |file|
14
+ excluded_files = %w[lib/sinatra/contrib.rb lib/sinatra/capture.rb lib/sinatra/engine_tracking.rb]
15
+ next if excluded_files.include?(file)
16
+ doc = File.read(file)[/^module Sinatra(\n)+( #[^\n]*\n)*/m].scan(/^ *#(?!#) ?(.*)\n/).join("\n")
17
+ file = "doc/#{file[4..-4].tr("/_", "-")}.rdoc"
18
+ Dir.mkdir "doc" unless File.directory? "doc"
19
+ puts "writing #{file}"
20
+ File.open(file, "w") { |f| f << doc }
21
+ end
22
+ end
23
+
24
+ task :all => [:readmes]
25
+ end
26
+
27
+ desc "generate documentation"
28
+ task :doc => 'doc:all'
29
+
30
+ desc "generate gemspec"
31
+ task 'sinatra-contrib.gemspec' do
32
+ content = File.read 'sinatra-contrib.gemspec'
33
+
34
+ fields = {
35
+ :authors => `git shortlog -sn`.scan(/[^\d\s].*/),
36
+ :email => `git shortlog -sne`.scan(/[^<]+@[^>]+/),
37
+ :files => `git ls-files`.split("\n").reject { |f| f =~ /^(\.|Gemfile)/ }
38
+ }
39
+
40
+ fields.each do |field, values|
41
+ updated = " s.#{field} = ["
42
+ updated << values.map { |v| "\n %p" % v }.join(',')
43
+ updated << "\n ]"
44
+ content.sub!(/ s\.#{field} = \[\n( .*\n)* \]/, updated)
45
+ end
46
+
47
+ content.sub! /(s\.version.*=\s+).*/, "\\1\"#{Sinatra::Contrib::VERSION}\""
48
+ File.open('sinatra-contrib.gemspec', 'w') { |f| f << content }
49
+ end
50
+
51
+ task :gemspec => 'sinatra-contrib.gemspec'
52
+
53
+ desc 'update travis config to correspond to sinatra'
54
+ task :travis, [:branch] do |t, a|
55
+ a.with_defaults :branch => :master
56
+ data = YAML.load open("https://raw.github.com/sinatra/sinatra/#{a.branch}/.travis.yml")
57
+ data["notifications"]["recipients"] << "ohhgabriel@gmail.com"
58
+ File.open('.travis.yml', 'w') { |f| f << data.to_yaml }
59
+ system 'git add .travis.yml && git diff --cached .travis.yml'
60
+ end
61
+
62
+ task :release => :gemspec do
63
+ sh <<-SH
64
+ rm -Rf sinatra-contrib*.gem &&
65
+ gem build sinatra-contrib.gemspec &&
66
+ gem install sinatra-contrib*.gem --local &&
67
+ gem push sinatra-contrib*.gem &&
68
+ git commit --allow-empty -a -m '#{Sinatra::Contrib::VERSION} release' &&
69
+ git tag -s v#{Sinatra::Contrib::VERSION} -m '#{Sinatra::Contrib::VERSION} release' &&
70
+ git tag -s #{Sinatra::Contrib::VERSION} -m '#{Sinatra::Contrib::VERSION} release' &&
71
+ git push && (git push sinatra || true) &&
72
+ git push --tags && (git push sinatra --tags || true)
73
+ SH
74
+ end
75
+
data/ideas.md ADDED
@@ -0,0 +1,29 @@
1
+ * Extension that does something like this:
2
+
3
+ def build(*)
4
+ if settings.memcached?
5
+ use Rack::Cache, :backend => :memcached
6
+ use Rack::Session::Memcached
7
+ # ...
8
+ end
9
+ super
10
+ end
11
+
12
+ * `sinatra-smart-cache`: update cache header only if arguments are more
13
+ restrictive than curent value, set caching headers that way for most helper
14
+ methods (i.e. `sass` or `send_file`)
15
+
16
+ * Some verbose logging extension: Log what filters, routes, error handlers,
17
+ templates, and so on is used.
18
+
19
+ * Form helpers, with forms as first class objects that accepts hashes or
20
+ something, so the form meta data can also be used to expose a JSON API or
21
+ similar, possibly defining routes (like "Sinatra's Hat"), strictly using
22
+ the ActiveModel API.
23
+
24
+ * Extend `sinatra-content-for` to support Liquid, Radius, Markaby, Nokogiri and
25
+ Builder. At least the first two probably involve patching Tilt.
26
+
27
+ * Rewrite of `sinatra-compass`?
28
+
29
+ * Helpers for HTML escaping and such.
@@ -0,0 +1,42 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/engine_tracking'
3
+ require 'backports'
4
+
5
+ module Sinatra
6
+ module Capture
7
+ include Sinatra::EngineTracking
8
+
9
+ DUMMIES = {
10
+ :haml => "!= capture_haml(*args, &block)",
11
+ :erb => "<% @capture = yield(*args) %>",
12
+ :slim => "== yield(*args)"
13
+ }
14
+
15
+ DUMMIES[:erubis] = DUMMIES[:erb]
16
+
17
+ def capture(*args, &block)
18
+ @capture = nil
19
+ if current_engine == :ruby
20
+ result = block[*args]
21
+ else
22
+ buffer = eval '_buf if defined?(_buf)', block.binding
23
+ old_buffer = buffer.dup if buffer
24
+ dummy = DUMMIES.fetch(current_engine)
25
+ options = { :layout => false, :locals => {:args => args, :block => block }}
26
+
27
+ buffer.try :clear
28
+ result = render(current_engine, dummy, options, &block)
29
+ end
30
+ result.strip.empty? && @capture ? @capture : result
31
+ ensure
32
+ buffer.try :replace, old_buffer
33
+ end
34
+
35
+ def capture_later(&block)
36
+ engine = current_engine
37
+ proc { |*a| with_engine(engine) { @capture = capture(*a, &block) }}
38
+ end
39
+ end
40
+
41
+ helpers Capture
42
+ end
@@ -0,0 +1,151 @@
1
+ require 'sinatra/base'
2
+ require 'yaml'
3
+
4
+ module Sinatra
5
+
6
+ # = Sinatra::ConfigFile
7
+ #
8
+ # <tt>Sinatra::ConfigFile</tt> is an extension that allows you to load the
9
+ # application's configuration from YAML files. It automatically detects if
10
+ # the files contains specific environment settings and it will use the
11
+ # corresponding to the current one.
12
+ #
13
+ # Within the application you can access those options through +settings+. If
14
+ # you try to get the value for a setting that hasn't been defined in the
15
+ # config file for the current environment, you will get whatever it was set
16
+ # to in the application.
17
+ #
18
+ # == Usage
19
+ #
20
+ # Once you have written your configurations to a YAML file you can tell the
21
+ # extension to load them. See below for more information about how these
22
+ # files are interpreted.
23
+ #
24
+ # For the examples, lets assume the following config.yml file:
25
+ #
26
+ # greeting: Welcome to my file configurable application
27
+ #
28
+ # === Classic Application
29
+ #
30
+ # require "sinatra"
31
+ # require "sinatra/config_file"
32
+ #
33
+ # config_file 'path/to/config.yml'
34
+ #
35
+ # get '/' do
36
+ # @greeting = settings.greeting
37
+ # haml :index
38
+ # end
39
+ #
40
+ # # The rest of your classic application code goes here...
41
+ #
42
+ # === Modular Application
43
+ #
44
+ # require "sinatra/base"
45
+ # require "sinatra/config_file"
46
+ #
47
+ # class MyApp < Sinatra::Base
48
+ # register Sinatra::ConfigFile
49
+ #
50
+ # config_file 'path/to/config.yml'
51
+ #
52
+ # get '/' do
53
+ # @greeting = settings.greeting
54
+ # haml :index
55
+ # end
56
+ #
57
+ # # The rest of your modular application code goes here...
58
+ # end
59
+ #
60
+ # === Config File Format
61
+ #
62
+ # In its most simple form this file is just a key-value list:
63
+ #
64
+ # foo: bar
65
+ # something: 42
66
+ # nested:
67
+ # a: 1
68
+ # b: 2
69
+ #
70
+ # But it also can provide specific environment configuration. There are two
71
+ # ways to do that: at the file level and at the setting level. They are
72
+ # illustrated, repsectively, as follows:
73
+ #
74
+ # development:
75
+ # foo: development
76
+ # bar: bar
77
+ # test:
78
+ # foo: test
79
+ # bar: bar
80
+ # production:
81
+ # foo: production
82
+ # bar: bar
83
+ #
84
+ # and
85
+ #
86
+ # foo:
87
+ # development: development
88
+ # test: test
89
+ # production: production
90
+ # bar: bar
91
+ #
92
+ # In either case, <tt>settings.foo</tt> will return the environment name, and
93
+ # <tt>settings.bar</tt> will return <tt>"bar"</tt>.
94
+ #
95
+ # Be aware that if you have a different environment, besides development,
96
+ # test and production, you will also need to adjust the +environments+
97
+ # setting. For instance, when you also have a staging environment:
98
+ #
99
+ # set :environments, %w{development test production staging}
100
+ #
101
+ module ConfigFile
102
+
103
+ # When the extension is registered sets the +environments+ setting to the
104
+ # traditional environments: development, test and production.
105
+ def self.registered(base)
106
+ base.set :environments, %w[test production development]
107
+ end
108
+
109
+ # Loads the configuration from the YAML files whose +paths+ are passed as
110
+ # arguments, filtering the settings for the current environment. Note that
111
+ # these +paths+ can actually be globs.
112
+ def config_file(*paths)
113
+ Dir.chdir(root || '.') do
114
+ paths.each do |pattern|
115
+ Dir.glob(pattern) do |file|
116
+ $stderr.puts "loading config file '#{file}'" if logging?
117
+ yaml = config_for_env(YAML.load_file(file)) || {}
118
+ yaml.each_pair do |key, value|
119
+ for_env = config_for_env(value)
120
+ set key, for_env unless value and for_env.nil? and respond_to? key
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ # Given a +hash+ with some application configuration it returns the
130
+ # settings applicable to the current environment. Note that this can only
131
+ # be done when all the keys of +hash+ are environment names included in the
132
+ # +environments+ setting (which is an Array of Strings). Also, the
133
+ # returned config is a indifferently accessible Hash, which means that you
134
+ # can get its values using Strings or Symbols as keys.
135
+ def config_for_env(hash)
136
+ if hash.respond_to? :keys and hash.keys.all? { |k| environments.include? k.to_s }
137
+ hash = hash[environment.to_s] || hash[environment.to_sym]
138
+ end
139
+
140
+ if hash.respond_to? :to_hash
141
+ indifferent_hash = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
142
+ indifferent_hash.merge hash.to_hash
143
+ else
144
+ hash
145
+ end
146
+ end
147
+ end
148
+
149
+ register ConfigFile
150
+ Delegator.delegate :config_file
151
+ end