sinatra-contrib 1.3.0

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