oahu-dragonfly 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. data/.rspec +1 -0
  2. data/.yardopts +24 -0
  3. data/Gemfile +30 -0
  4. data/History.md +323 -0
  5. data/LICENSE +20 -0
  6. data/README.md +88 -0
  7. data/Rakefile +50 -0
  8. data/VERSION +1 -0
  9. data/config.ru +14 -0
  10. data/docs.watchr +1 -0
  11. data/dragonfly.gemspec +297 -0
  12. data/extra_docs/Analysers.md +66 -0
  13. data/extra_docs/Caching.md +23 -0
  14. data/extra_docs/Configuration.md +124 -0
  15. data/extra_docs/Couch.md +49 -0
  16. data/extra_docs/DataStorage.md +153 -0
  17. data/extra_docs/Encoding.md +67 -0
  18. data/extra_docs/GeneralUsage.md +121 -0
  19. data/extra_docs/Generators.md +60 -0
  20. data/extra_docs/Heroku.md +50 -0
  21. data/extra_docs/ImageMagick.md +125 -0
  22. data/extra_docs/Index.md +33 -0
  23. data/extra_docs/MimeTypes.md +40 -0
  24. data/extra_docs/Models.md +272 -0
  25. data/extra_docs/Mongo.md +45 -0
  26. data/extra_docs/Processing.md +77 -0
  27. data/extra_docs/Rack.md +52 -0
  28. data/extra_docs/Rails2.md +57 -0
  29. data/extra_docs/Rails3.md +62 -0
  30. data/extra_docs/Sinatra.md +25 -0
  31. data/extra_docs/URLs.md +169 -0
  32. data/features/images.feature +47 -0
  33. data/features/no_processing.feature +14 -0
  34. data/features/rails_3.0.5.feature +8 -0
  35. data/features/steps/common_steps.rb +8 -0
  36. data/features/steps/dragonfly_steps.rb +66 -0
  37. data/features/steps/rails_steps.rb +28 -0
  38. data/features/support/env.rb +13 -0
  39. data/features/support/setup.rb +32 -0
  40. data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
  41. data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
  42. data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
  43. data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -0
  44. data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
  45. data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
  46. data/fixtures/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
  47. data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
  48. data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
  49. data/fixtures/rails_3.0.5/template.rb +20 -0
  50. data/irbrc.rb +18 -0
  51. data/lib/dragonfly.rb +55 -0
  52. data/lib/dragonfly/active_model_extensions.rb +13 -0
  53. data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
  54. data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
  55. data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
  56. data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
  57. data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
  58. data/lib/dragonfly/analyser.rb +58 -0
  59. data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
  60. data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
  61. data/lib/dragonfly/app.rb +172 -0
  62. data/lib/dragonfly/config/heroku.rb +19 -0
  63. data/lib/dragonfly/config/image_magick.rb +6 -0
  64. data/lib/dragonfly/config/rails.rb +20 -0
  65. data/lib/dragonfly/configurable.rb +207 -0
  66. data/lib/dragonfly/core_ext/array.rb +7 -0
  67. data/lib/dragonfly/core_ext/hash.rb +7 -0
  68. data/lib/dragonfly/core_ext/object.rb +12 -0
  69. data/lib/dragonfly/core_ext/string.rb +9 -0
  70. data/lib/dragonfly/core_ext/symbol.rb +9 -0
  71. data/lib/dragonfly/data_storage.rb +9 -0
  72. data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
  73. data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
  74. data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
  75. data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
  76. data/lib/dragonfly/encoder.rb +13 -0
  77. data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
  78. data/lib/dragonfly/function_manager.rb +71 -0
  79. data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
  80. data/lib/dragonfly/generator.rb +9 -0
  81. data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
  82. data/lib/dragonfly/image_magick/analyser.rb +51 -0
  83. data/lib/dragonfly/image_magick/config.rb +41 -0
  84. data/lib/dragonfly/image_magick/encoder.rb +57 -0
  85. data/lib/dragonfly/image_magick/generator.rb +145 -0
  86. data/lib/dragonfly/image_magick/processor.rb +99 -0
  87. data/lib/dragonfly/image_magick/utils.rb +72 -0
  88. data/lib/dragonfly/image_magick_utils.rb +4 -0
  89. data/lib/dragonfly/job.rb +451 -0
  90. data/lib/dragonfly/job_builder.rb +39 -0
  91. data/lib/dragonfly/job_definitions.rb +26 -0
  92. data/lib/dragonfly/job_endpoint.rb +15 -0
  93. data/lib/dragonfly/loggable.rb +28 -0
  94. data/lib/dragonfly/middleware.rb +20 -0
  95. data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
  96. data/lib/dragonfly/processor.rb +9 -0
  97. data/lib/dragonfly/rails/images.rb +27 -0
  98. data/lib/dragonfly/response.rb +97 -0
  99. data/lib/dragonfly/routed_endpoint.rb +40 -0
  100. data/lib/dragonfly/serializer.rb +32 -0
  101. data/lib/dragonfly/server.rb +113 -0
  102. data/lib/dragonfly/simple_cache.rb +23 -0
  103. data/lib/dragonfly/temp_object.rb +175 -0
  104. data/lib/dragonfly/url_mapper.rb +78 -0
  105. data/samples/beach.png +0 -0
  106. data/samples/egg.png +0 -0
  107. data/samples/round.gif +0 -0
  108. data/samples/sample.docx +0 -0
  109. data/samples/taj.jpg +0 -0
  110. data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
  111. data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
  112. data/spec/dragonfly/analyser_spec.rb +123 -0
  113. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
  114. data/spec/dragonfly/app_spec.rb +135 -0
  115. data/spec/dragonfly/configurable_spec.rb +461 -0
  116. data/spec/dragonfly/core_ext/array_spec.rb +19 -0
  117. data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
  118. data/spec/dragonfly/core_ext/string_spec.rb +17 -0
  119. data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
  120. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
  121. data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
  122. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
  123. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
  124. data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
  125. data/spec/dragonfly/function_manager_spec.rb +154 -0
  126. data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
  127. data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
  128. data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
  129. data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
  130. data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
  131. data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
  132. data/spec/dragonfly/job_builder_spec.rb +37 -0
  133. data/spec/dragonfly/job_definitions_spec.rb +35 -0
  134. data/spec/dragonfly/job_endpoint_spec.rb +173 -0
  135. data/spec/dragonfly/job_spec.rb +1046 -0
  136. data/spec/dragonfly/loggable_spec.rb +80 -0
  137. data/spec/dragonfly/middleware_spec.rb +47 -0
  138. data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
  139. data/spec/dragonfly/serializer_spec.rb +61 -0
  140. data/spec/dragonfly/server_spec.rb +278 -0
  141. data/spec/dragonfly/simple_cache_spec.rb +27 -0
  142. data/spec/dragonfly/temp_object_spec.rb +306 -0
  143. data/spec/dragonfly/url_mapper_spec.rb +126 -0
  144. data/spec/functional/deprecations_spec.rb +51 -0
  145. data/spec/functional/image_magick_app_spec.rb +27 -0
  146. data/spec/functional/model_urls_spec.rb +85 -0
  147. data/spec/functional/remote_on_the_fly_spec.rb +51 -0
  148. data/spec/functional/to_response_spec.rb +31 -0
  149. data/spec/spec_helper.rb +51 -0
  150. data/spec/support/argument_matchers.rb +19 -0
  151. data/spec/support/image_matchers.rb +47 -0
  152. data/spec/support/simple_matchers.rb +53 -0
  153. data/yard/handlers/configurable_attr_handler.rb +38 -0
  154. data/yard/setup.rb +15 -0
  155. data/yard/templates/default/fulldoc/html/css/common.css +107 -0
  156. data/yard/templates/default/layout/html/layout.erb +89 -0
  157. data/yard/templates/default/module/html/configuration_summary.erb +31 -0
  158. data/yard/templates/default/module/setup.rb +17 -0
  159. metadata +544 -0
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'deprecations' do
4
+
5
+ before(:each) do
6
+ @app = test_app
7
+ end
8
+
9
+ describe "url_suffix" do
10
+ it "should give an appropriate error" do
11
+ @app.configure do |c|
12
+ expect{
13
+ c.url_suffix = 'darble'
14
+ }.to raise_error(NoMethodError, /deprecated.*please use url_format/)
15
+ end
16
+ end
17
+ end
18
+
19
+ describe "url_path_prefix" do
20
+ it "should give an appropriate error" do
21
+ @app.configure do |c|
22
+ expect{
23
+ c.url_path_prefix = '/darble'
24
+ }.to raise_error(NoMethodError, /deprecated.*please use url_format/)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "middleware" do
30
+ it "should give an appropriate error" do
31
+ app = Rack::Builder.new do
32
+ use Dragonfly::Middleware, :images, '/media'
33
+ run proc{[200, {}, []]}
34
+ end
35
+ expect{
36
+ app.call({})
37
+ }.to raise_error(ArgumentError, /deprecated/)
38
+ end
39
+ end
40
+
41
+ describe "infer_mime_type_from_file_ext" do
42
+ it "should give an appropriate error" do
43
+ @app.configure do |c|
44
+ expect{
45
+ c.infer_mime_type_from_file_ext = false
46
+ }.to raise_error(NoMethodError, /deprecated.*please use trust_file_extensions = false/)
47
+ end
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe "a configured imagemagick app" do
4
+
5
+ before(:each) do
6
+ @app = Dragonfly[:images].configure_with(:imagemagick)
7
+ end
8
+
9
+ describe "convert command path" do
10
+ before(:each) do
11
+ @processor = @app.processor.get_registered(Dragonfly::ImageMagick::Processor)
12
+ end
13
+
14
+ it "should default to 'convert'" do
15
+ @processor.convert_command.should == 'convert'
16
+ end
17
+
18
+ it "should change when configured through the app" do
19
+ @app.configure do |c|
20
+ c.convert_command = '/usr/eggs'
21
+ end
22
+ @processor.convert_command.should == '/usr/eggs'
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,85 @@
1
+ require 'dragonfly/active_model_extensions/spec_helper'
2
+ require 'tempfile'
3
+
4
+ describe "model urls" do
5
+
6
+ def new_tempfile(data='HELLO', filename='hello.txt')
7
+ tempfile = Tempfile.new('test')
8
+ tempfile.write(data)
9
+ tempfile.rewind
10
+ tempfile.stub!(:original_filename).and_return(filename)
11
+ tempfile
12
+ end
13
+
14
+ before(:each) do
15
+ @app = test_app.configure do |c|
16
+ c.url_format = '/media/:job/:basename.:format'
17
+ end
18
+ @app.define_macro(MyModel, :image_accessor)
19
+ Item.class_eval do
20
+ image_accessor :preview_image # has name etc.
21
+ image_accessor :other_image # doesn't have magic stuff
22
+ end
23
+ @item = Item.new
24
+ end
25
+
26
+ it "should include the name in the url if it has the magic attribute" do
27
+ @item.preview_image = new_tempfile
28
+ @item.save!
29
+ item = Item.find(@item.id)
30
+ item.preview_image.url.should =~ %r{^/media/\w+/hello\.txt$}
31
+ end
32
+
33
+ it "should work without the name if the name magic attr doesn't exist" do
34
+ @item.other_image = new_tempfile
35
+ @item.save!
36
+ item = Item.find(@item.id)
37
+ item.other_image.url.should =~ %r{^/media/\w+$}
38
+ end
39
+
40
+ it "should include the name in the url even if it has no ext" do
41
+ @item.preview_image = new_tempfile("hello", 'hello')
42
+ @item.save!
43
+ item = Item.find(@item.id)
44
+ item.preview_image.url.should =~ %r{^/media/\w+/hello$}
45
+ end
46
+
47
+ it "should change the ext when there's an encoding step" do
48
+ @item.preview_image = new_tempfile
49
+ @item.save!
50
+ item = Item.find(@item.id)
51
+ item.preview_image.encode(:bum).url.should =~ %r{^/media/\w+/hello\.bum$}
52
+ end
53
+
54
+ it "should not include the name if it has none" do
55
+ @item.preview_image = "HELLO"
56
+ @item.save!
57
+ item = Item.find(@item.id)
58
+ item.preview_image.url.should =~ %r{^/media/\w+$}
59
+ end
60
+
61
+ it "should have an ext when there's an encoding step but no name" do
62
+ @item.preview_image = "HELLO"
63
+ @item.save!
64
+ item = Item.find(@item.id)
65
+ item.preview_image.encode(:bum).url.should =~ %r{^/media/\w+\.bum$}
66
+ end
67
+
68
+ it "should work as normal with dos protection" do
69
+ @app.server.protect_from_dos_attacks = true
70
+ @item.preview_image = new_tempfile
71
+ @item.save!
72
+ item = Item.find(@item.id)
73
+ item.preview_image.url.should =~ %r{^/media/\w+/hello\.txt\?sha=\w+$}
74
+ end
75
+
76
+ it "should allow configuring the url" do
77
+ @app.configure do |c|
78
+ c.url_format = '/img/:job'
79
+ end
80
+ @item.preview_image = new_tempfile
81
+ @item.save!
82
+ item = Item.find(@item.id)
83
+ item.preview_image.url.should =~ %r{^/img/\w+$}
84
+ end
85
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe "remote on-the-fly urls" do
4
+
5
+ THUMBS = {}
6
+
7
+ before(:each) do
8
+ @app = test_app.configure do |c|
9
+ c.generator.add :test do
10
+ "TEST"
11
+ end
12
+ c.server.before_serve do |job, env|
13
+ uid = job.store(:path => 'yay.txt')
14
+ THUMBS[job.serialize] = uid
15
+ end
16
+ c.define_url do |app, job, opts|
17
+ uid = THUMBS[job.serialize]
18
+ if uid
19
+ app.datastore.url_for(uid)
20
+ else
21
+ app.server.url_for(job)
22
+ end
23
+ end
24
+ c.datastore = Dragonfly::DataStorage::FileDataStore.new
25
+ c.datastore.root_path = '/var/tmp/dragonfly'
26
+ c.datastore.server_root = '/var/tmp'
27
+ end
28
+ @job = @app.generate(:test)
29
+ end
30
+
31
+ after(:each) do
32
+ THUMBS.delete_if{true}
33
+ FileUtils.rm_f('/var/tmp/dragonfly/yay.txt')
34
+ end
35
+
36
+ it "should give the url for the server" do
37
+ @job.url.should == "/#{@job.serialize}"
38
+ end
39
+
40
+ it "should store the content when first called" do
41
+ File.exist?('/var/tmp/dragonfly/yay.txt').should be_false
42
+ @app.server.call('PATH_INFO' => @job.url, 'REQUEST_METHOD' => 'GET')
43
+ File.read('/var/tmp/dragonfly/yay.txt').should == 'TEST'
44
+ end
45
+
46
+ it "should point to the external url the second time" do
47
+ @app.server.call('PATH_INFO' => @job.url, 'REQUEST_METHOD' => 'GET')
48
+ @job.url.should == '/dragonfly/yay.txt'
49
+ end
50
+
51
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe "getting rack response directly" do
4
+
5
+ before(:each) do
6
+ @app = Dragonfly[:to_response].configure do |c|
7
+ c.generator.add :test do
8
+ "bunheads"
9
+ end
10
+ end
11
+ end
12
+
13
+ it "should give a rack response" do
14
+ response = @app.generate(:test, 1, 1).to_response
15
+ response.should be_a(Array)
16
+ response.length.should == 3
17
+ response[0].should == 200
18
+ response[1]['Content-Type'].should == 'application/octet-stream'
19
+ response[2].data.should == 'bunheads'
20
+ end
21
+
22
+ it "should allow passing in the env" do
23
+ response = @app.generate(:test, 1, 1).to_response('REQUEST_METHOD' => 'POST')
24
+ response.should be_a(Array)
25
+ response.length.should == 3
26
+ response[0].should == 405
27
+ response[1]['Content-Type'].should == 'text/plain'
28
+ response[2].should == ["POST method not allowed"]
29
+ end
30
+
31
+ end
@@ -0,0 +1,51 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup(:default, :test)
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'rspec'
8
+ require 'dragonfly'
9
+ require 'fileutils'
10
+
11
+ require 'webmock/rspec'
12
+
13
+ # Requires supporting files with custom matchers and macros, etc,
14
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
15
+
16
+ SAMPLES_DIR = File.expand_path(File.dirname(__FILE__) + '/../samples') unless defined?(SAMPLES_DIR)
17
+
18
+ def todo
19
+ raise "TODO"
20
+ end
21
+
22
+ require 'logger'
23
+ LOG_FILE = File.dirname(__FILE__) + '/spec.log' unless defined?(LOG_FILE)
24
+ FileUtils.rm_rf(LOG_FILE)
25
+ def mock_app(extra_stubs={})
26
+ mock('app', {
27
+ :datastore => mock('datastore', :store => 'some_uid', :retrieve => ["SOME_DATA", {}], :destroy => nil),
28
+ :processor => mock('processor', :process => "SOME_PROCESSED_DATA"),
29
+ :encoder => mock('encoder', :encode => "SOME_ENCODED_DATA"),
30
+ :analyser => mock('analyser', :analyse => "some_result", :analysis_methods => Module.new),
31
+ :generator => mock('generator', :generate => "SOME_GENERATED_DATA"),
32
+ :log => Logger.new(LOG_FILE),
33
+ :cache_duration => 10000,
34
+ :job_definitions => Module.new
35
+ }.merge(extra_stubs)
36
+ )
37
+ end
38
+
39
+ def test_app
40
+ Dragonfly::App.send(:new)
41
+ end
42
+
43
+ def suppressing_stderr
44
+ original_stderr = $stderr.dup
45
+ tempfile = Tempfile.new('stderr')
46
+ $stderr.reopen(tempfile)
47
+ yield
48
+ ensure
49
+ tempfile.close!
50
+ $stderr.reopen(original_stderr)
51
+ end
@@ -0,0 +1,19 @@
1
+ def string_matching(regexp)
2
+ Spec::Mocks::ArgumentMatchers::RegexpMatcher.new(regexp)
3
+ end
4
+
5
+ class TempObjectArgumentMatcher
6
+ def initialize(data, opts)
7
+ @data = data
8
+ @opts = opts
9
+ end
10
+ def ==(actual)
11
+ actual.is_a?(Dragonfly::TempObject) &&
12
+ actual.data == @data &&
13
+ @opts.all?{|k,v| actual.send(k) == v }
14
+ end
15
+ end
16
+
17
+ def a_temp_object_with_data(data, opts={})
18
+ TempObjectArgumentMatcher.new(data, opts)
19
+ end
@@ -0,0 +1,47 @@
1
+ def image_properties(image)
2
+ if image.is_a?(Tempfile)
3
+ tempfile = image
4
+ else
5
+ tempfile = Tempfile.new('image')
6
+ tempfile.write(image.is_a?(Dragonfly::TempObject) ? image.data : image)
7
+ tempfile.close
8
+ end
9
+ details = `identify #{tempfile.path}`
10
+ # example of details string:
11
+ # myimage.png PNG 200x100 200x100+0+0 8-bit DirectClass 31.2kb
12
+ filename, format, geometry, geometry_2, depth, image_class, size = details.split(' ')
13
+ width, height = geometry.split('x')
14
+ {
15
+ :filename => filename,
16
+ :format => format.downcase,
17
+ :width => width,
18
+ :height => height,
19
+ :depth => depth,
20
+ :image_class => image_class,
21
+ :size => size
22
+ }
23
+ end
24
+
25
+ RSpec::Matchers.define :have_width do |width|
26
+ match do |given|
27
+ width.should === image_properties(given)[:width].to_i
28
+ end
29
+ end
30
+
31
+ RSpec::Matchers.define :have_height do |height|
32
+ match do |given|
33
+ height.should === image_properties(given)[:height].to_i
34
+ end
35
+ end
36
+
37
+ RSpec::Matchers.define :have_format do |format|
38
+ match do |given|
39
+ image_properties(given)[:format].should == format
40
+ end
41
+ end
42
+
43
+ RSpec::Matchers.define :have_size do |size|
44
+ match do |given|
45
+ image_properties(given)[:size].should == size
46
+ end
47
+ end
@@ -0,0 +1,53 @@
1
+ RSpec::Matchers.define :match_url do |url|
2
+ match do |given|
3
+ given_path, given_query_string = given.split('?')
4
+ path, query_string = url.split('?')
5
+
6
+ path == given_path && given_query_string.split('&').sort == query_string.split('&').sort
7
+ end
8
+ end
9
+
10
+ RSpec::Matchers.define :be_an_empty_directory do
11
+ match do |given|
12
+ Dir.entries(given) == ['.','..']
13
+ end
14
+ end
15
+
16
+ RSpec::Matchers.define :include_hash do |hash|
17
+ match do |given|
18
+ given.merge(hash) == given
19
+ end
20
+ end
21
+
22
+ def memory_usage
23
+ GC.start # Garbage collect
24
+ `ps -o rss= -p #{$$}`.strip.to_i
25
+ end
26
+
27
+ RSpec::Matchers.define :leak_memory do
28
+ match do |given|
29
+ memory_before = memory_usage
30
+ given.call
31
+ memory_after = memory_usage
32
+ result = memory_after > memory_before
33
+ puts "#{memory_after} > #{memory_before}" if result
34
+ result
35
+ end
36
+ end
37
+
38
+ RSpec::Matchers.define :match_attachment_classes do |classes|
39
+ match do |given_classes|
40
+ given_classes.length == classes.length &&
41
+ classes.zip(given_classes).all? do |(klass, given)|
42
+ given.model_class == klass[0] && given.attribute == klass[1] && given.app == klass[2]
43
+ end
44
+ end
45
+ end
46
+
47
+ RSpec::Matchers.define :be_a_text_response do
48
+ match do |given_response|
49
+ given_response.status.should == 200
50
+ given_response.body.length.should > 0
51
+ given_response.content_type.should == 'text/plain'
52
+ end
53
+ end
@@ -0,0 +1,38 @@
1
+ class ConfigurableAttrHandler < YARD::Handlers::Ruby::Legacy::Base
2
+ handles(/^\s*configurable_attr/)
3
+
4
+ def process
5
+ namespace[:configurable_attributes] ||= []
6
+
7
+ attribute = token_to_object(statement.tokens[2])
8
+ comments = statement.comments.join(' ') if statement.comments
9
+
10
+ if statement.block
11
+ # e.g. configurable_attr :datastore do FileDataStore.new end
12
+ lazy_default_value = statement.block.to_s
13
+ else
14
+ # e.g. configurable_attr :fallback_mime_type, 'application/octet-stream'
15
+ default_value = token_to_object(statement.tokens[5..-1])
16
+ end
17
+ namespace[:configurable_attributes] << {
18
+ :attribute => attribute,
19
+ :default_value => default_value,
20
+ :lazy_default_value => lazy_default_value,
21
+ :comments => comments
22
+ }
23
+ end
24
+
25
+ private
26
+
27
+ def token_to_object(token)
28
+ if token
29
+ if token.is_a?(YARD::Parser::Ruby::Legacy::TokenList)
30
+ eval(token.to_s)
31
+ else # is a single token
32
+ eval(token.text)
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+