oahu-dragonfly 0.8.2

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