strelka 0.4.0 → 0.5.0.pre.393

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58ca9bc4fbcc4953f0b9fb9b15407b726b0a9512
4
- data.tar.gz: 946729ae577f2cd5496b3a14542094abb35ec907
3
+ metadata.gz: 1d2cffaf505aa41496b0ce345534e70d6f4b45a0
4
+ data.tar.gz: c922b2aa4deafe3472b9be7d2d960237dc2e2b11
5
5
  SHA512:
6
- metadata.gz: 429cab795c50159c7fdad07e17ecf0da7dbf6d43ef6e5798752d942a371dd592292815393c89563a0f29da887943b576fc7580a3d7ac1b06c091bae56d66bd99
7
- data.tar.gz: 27c80311955501589a68d377e90c4c532f3acd3a074c648a4d5ea9eefc9246a6eb8669793c07583146bb9ef3cdd0e689440b8912dd37f82ac703f4a34d5a7b64
6
+ metadata.gz: 295a62542aae175dd4c70d425fc70f43d314412db557a01989aa63b015931cdf20cad5793fefd4e15a237f49d0f50a17c95b72b5905f321a260520ba4c13e06f
7
+ data.tar.gz: 590d6dfab3b2a652e916b9e78ad497440b5e5de314abbd12b5c289fd917d43a1c9e4b212ec55fdc2d030693ef312ea44d8ce0b530c140ee5c714241388a0ae0d
checksums.yaml.gz.sig CHANGED
@@ -1 +1 @@
1
- ���~&U�ϱ�ʺ��� ��ؿ�G��!$) e���'F��n���z_a���a�4��'��v@ھ��$��ev�\�a:��#'�����j+��*�A��jM�!�z1ע8xs��ѷILR���\ ~_'�/�m��1hr<i����S���pfj ��'Z���yu�����:ϟe���h�q ��@t�ԭc���y���hQ��gq���iv���t)��TK� �%~E ��勐>l�-e
1
+ Q�]O$SS������U��pMAxq�T6��b?g7, ���C�����:�;|vN��ϤY�-�DΚ˴����[h���ŝ�t��؎���D���æ�}�٧л��^[h�o���ަ�5鑉gU��ַӢ�O�AOe���2�N���8�����L�dB����2��Ry~�����1�с�L'%A��B�:�@00!Cu���4��YQb[J-��3g�r�+�<DUb��
data/Rakefile CHANGED
@@ -27,7 +27,7 @@ hoespec = Hoe.spec 'strelka' do
27
27
  self.dependency 'inversion', '~> 0.12'
28
28
  self.dependency 'loggability', '~> 0.5'
29
29
  self.dependency 'mongrel2', '~> 0.36'
30
- self.dependency 'pluggability', '~> 0.0'
30
+ self.dependency 'pluggability', '~> 0.2'
31
31
  self.dependency 'sysexits', '~> 1.1'
32
32
  self.dependency 'trollop', '~> 2.0'
33
33
  self.dependency 'uuidtools', '~> 2.1'
@@ -21,21 +21,7 @@ require 'strelka/httpresponse/negotiation'
21
21
  #
22
22
  # plugins :routing, :negotiation
23
23
  #
24
- # add_content_type :tnetstring, 'text/x-tnetstring' do |response|
25
- # tnetstr = nil
26
- # begin
27
- # response.body.rewind
28
- # tnetstr = TNetString.dump( response.body )
29
- # rescue => err
30
- # self.log.error "%p while transforming entity body to a TNetString: %s" %
31
- # [ err.class, err.message ]
32
- # return false
33
- # else
34
- # response.body = tnetstr
35
- # response.content_type = 'text/x-tnetstring'
36
- # return true
37
- # end
38
- # end
24
+ # add_content_type :tnetstring, 'text/x-tnetstring', TNetstring.method( :dump )
39
25
  #
40
26
  # end # class UserService
41
27
  #
@@ -50,31 +36,16 @@ module Strelka::App::Negotiation
50
36
  # Class methods to add to classes with content-negotiation.
51
37
  module ClassMethods # :nodoc:
52
38
 
53
- # Content-type tranform registry, keyed by name
54
- @content_type_transforms = {}
55
- attr_reader :content_type_transforms
56
-
57
- # Content-type transform names, keyed by mimetype
58
- @transform_names = {}
59
- attr_reader :transform_names
60
-
61
-
62
- ### Extension callback -- add instance variables to extending objects.
63
- def inherited( subclass )
64
- super
65
- subclass.instance_variable_set( :@content_type_transforms, @content_type_transforms.dup )
66
- subclass.instance_variable_set( :@transform_names, @transform_names.dup )
67
- end
68
-
69
-
70
39
  ### Define a new media-type associated with the specified +name+ and +mimetype+. Responses
71
- ### whose requests accept content of the given +mimetype+ will pass their response to the
72
- ### specified +transform_block+, which should re-write the response's entity body if it can
73
- ### transform it to its mimetype. If it successfully does so, it should return +true+, else
74
- ### the next-best mimetype's transform will be called, etc.
75
- def add_content_type( name, mimetype, &transform_block )
76
- self.transform_names[ mimetype ] = name
77
- self.content_type_transforms[ name ] = transform_block
40
+ ### whose requests accept content of the given +mimetype+ will #call the
41
+ ### specified +callback+ with the current response body, and should return the
42
+ ### transformed body. If the conversion failed, the callback can either raise an
43
+ ### exception or return +nil+, either of which will continue on to any remaining
44
+ ### transforms. If no +callback+ is given, the method's block will be used.
45
+ def add_content_type( name, mimetype, callback=nil ) # :yield: response.body
46
+ callback ||= Proc.new # Use the block
47
+ Strelka::HTTPResponse::Negotiation.mimetype_map[ name.to_sym ] = mimetype
48
+ Strelka::HTTPResponse::Negotiation.stringifiers[ mimetype ] = callback
78
49
  end
79
50
 
80
51
  end # module ClassMethods
@@ -8,6 +8,7 @@ require 'yajl'
8
8
 
9
9
  require 'strelka/constants'
10
10
  require 'strelka/exceptions'
11
+ require 'strelka/mixins'
11
12
  require 'strelka/httpresponse' unless defined?( Strelka::HTTPResponse )
12
13
 
13
14
 
@@ -23,11 +24,12 @@ require 'strelka/httpresponse' unless defined?( Strelka::HTTPResponse )
23
24
  # is acceptable according to its request's `Accept*` headers.
24
25
  #
25
26
  module Strelka::HTTPResponse::Negotiation
27
+ extend Strelka::MethodUtilities
26
28
  include Strelka::Constants
27
29
 
28
30
  # TODO: Perhaps replace this with something like this:
29
31
  # Mongrel2::Config::Mimetype.to_hash( :extension => :mimetype )
30
- BUILTIN_MIMETYPES = {
32
+ BUILTIN_MIMETYPE_MAP = {
31
33
  :html => 'text/html',
32
34
  :text => 'text/plain',
33
35
 
@@ -43,10 +45,10 @@ module Strelka::HTTPResponse::Negotiation
43
45
  :atom => 'application/atom+xml',
44
46
  }
45
47
 
46
- # A collection of stringifier callbacks, keyed by mimetype. If an object other
47
- # than a String is returned by a content callback, and an entry for the callback's
48
- # mimetype exists in this Hash, it will be #call()ed to stringify the object.
49
- STRINGIFIERS = {
48
+ # A collection of default stringifier callbacks, keyed by mimetype. If an entry
49
+ # for the content-negotiation callback's mimetype exists in this Hash, it will
50
+ # be #call()ed on the callback's return value to stringify the body.
51
+ BUILTIN_STRINGIFIERS = {
50
52
  'application/x-yaml' => YAML.method( :dump ),
51
53
  'application/json' => Yajl.method( :dump ),
52
54
  'text/plain' => Proc.new {|obj| obj.to_s },
@@ -62,6 +64,18 @@ module Strelka::HTTPResponse::Negotiation
62
64
  ]
63
65
 
64
66
 
67
+ ##
68
+ # The Hash of symbolic mediatypes of the form:
69
+ # { <name (Symbol)> => <mimetype> }
70
+ singleton_attr_reader :mimetype_map
71
+ @mimetype_map = BUILTIN_MIMETYPE_MAP.dup
72
+
73
+ ##
74
+ # The Hash of stringification callbacks, keyed by mimetype.
75
+ singleton_attr_reader :stringifiers
76
+ @stringifiers = BUILTIN_STRINGIFIERS.dup
77
+
78
+
65
79
  ### Add some instance variables for negotiation.
66
80
  def initialize( * )
67
81
  @mediatype_callbacks = {}
@@ -267,7 +281,11 @@ module Strelka::HTTPResponse::Negotiation
267
281
  ### to HTTP::OK.
268
282
  def for( *mediatypes, &callback )
269
283
  mediatypes.each do |mimetype|
270
- mimetype = BUILTIN_MIMETYPES[ mimetype ] if mimetype.is_a?( Symbol )
284
+ if mimetype.is_a?( Symbol )
285
+ mimetype = Strelka::HTTPResponse::Negotiation.mimetype_map[ mimetype ] or
286
+ raise "No known mimetype mapped to %p" % [ mimetype ]
287
+ end
288
+
271
289
  self.mediatype_callbacks[ mimetype ] = callback
272
290
  end
273
291
 
@@ -307,17 +325,19 @@ module Strelka::HTTPResponse::Negotiation
307
325
  ### until one returns a true-ish value, which becomes the new entity
308
326
  ### body. If the body object is not a String,
309
327
  def transform_content_type
328
+ self.log.debug "Applying content-type transforms (if any)"
310
329
  return if self.mediatype_callbacks.empty?
311
330
 
312
- self.log.debug "Applying content-type transforms (if any)"
331
+ self.log.debug " transform callbacks registered: %p" % [ self.mediatype_callbacks ]
313
332
  self.better_mediatypes.each do |mediatype|
314
333
  callbacks = self.mediatype_callbacks.find_all do |mimetype, _|
315
334
  mediatype =~ mimetype
316
335
  end
317
336
 
318
337
  if callbacks.empty?
319
- self.log.debug " no transforms for %s" % [ mediatype ]
338
+ self.log.debug " no transforms for %s" % [ mediatype ]
320
339
  else
340
+ self.log.debug " %d transform/s for %s" % [ callbacks.length, mediatype ]
321
341
  callbacks.each do |mimetype, callback|
322
342
  return if self.try_content_type_callback( mimetype, callback )
323
343
  end
@@ -334,9 +354,13 @@ module Strelka::HTTPResponse::Negotiation
334
354
 
335
355
  new_body = callback.call( mimetype ) or return false
336
356
 
337
- self.log.debug " successfully transformed: %p! Setting up response." % [ new_body ]
338
- new_body = STRINGIFIERS[ mimetype ].call( new_body ) if
339
- STRINGIFIERS.key?( mimetype ) && !new_body.is_a?( String )
357
+ self.log.debug " successfully transformed: %p! Setting up response." % [ new_body.class ]
358
+ stringifiers = Strelka::HTTPResponse::Negotiation.stringifiers
359
+ if stringifiers.key?( mimetype )
360
+ new_body = stringifiers[ mimetype ].call( new_body )
361
+ else
362
+ self.log.debug " no stringifier registered for %p" % [ mimetype ]
363
+ end
340
364
 
341
365
  self.body = new_body
342
366
  self.content_type = mimetype.dup # :TODO: Why is this frozen?
@@ -512,7 +536,7 @@ module Strelka::HTTPResponse::Negotiation
512
536
 
513
537
  # Don't close the FD when this IO goes out of scope
514
538
  oldbody = self.body
515
- oldbody.auto_close = false
539
+ oldbody.autoclose = false
516
540
 
517
541
  # Re-open the same file descriptor, but transcoding to the wanted encoding
518
542
  self.body = IO.for_fd( oldbody.fileno, internal_encoding: enc )
data/lib/strelka.rb CHANGED
@@ -24,7 +24,7 @@ module Strelka
24
24
  log_as :strelka
25
25
 
26
26
  # Library version constant
27
- VERSION = '0.4.0'
27
+ VERSION = '0.5.0'
28
28
 
29
29
  # Version-control revision constant
30
30
  REVISION = %q$Revision: 49ae27e4588e $
@@ -46,6 +46,19 @@ describe Strelka::App::Negotiation do
46
46
  def initialize( appid='conneg-test', sspec=TEST_SEND_SPEC, rspec=TEST_RECV_SPEC )
47
47
  super
48
48
  end
49
+
50
+ add_content_type :tnetstring, 'text/x-tnetstring', TNetstring.method(:dump)
51
+
52
+ def handle_request( req )
53
+ super do
54
+ res = req.response
55
+ res.for( :tnetstring ) {[ 'an', {'array' => 'of stuff'} ]}
56
+ res.for( :html ) do
57
+ "<html><head><title>Yep</title></head><body>Yeah!</body></html>"
58
+ end
59
+ res
60
+ end
61
+ end
49
62
  end
50
63
  end
51
64
 
@@ -54,18 +67,6 @@ describe Strelka::App::Negotiation do
54
67
  end
55
68
 
56
69
 
57
- it "has its config inherited by subclasses" do
58
- @app.add_content_type :text, 'text/plain' do
59
- "It's all text now, baby"
60
- end
61
- subclass = Class.new( @app )
62
-
63
- subclass.transform_names.should == @app.transform_names
64
- subclass.transform_names.should_not equal( @app.transform_names )
65
- subclass.content_type_transforms.should == @app.content_type_transforms
66
- subclass.content_type_transforms.should_not equal( @app.content_type_transforms )
67
- end
68
-
69
70
  it "gets requests that have been extended with content-negotiation" do
70
71
  req = @request_factory.get( '/service/user/estark' )
71
72
  @app.new.handle( req )
@@ -80,6 +81,13 @@ describe Strelka::App::Negotiation do
80
81
  should include( Strelka::HTTPResponse::Negotiation )
81
82
  end
82
83
 
84
+ it "adds custom content-type transforms to outgoing responses" do
85
+ req = @request_factory.get( '/service/user/astark', :accept => 'text/x-tnetstring' )
86
+ res = @app.new.handle( req )
87
+ res.content_type.should == 'text/x-tnetstring'
88
+ res.body.read.should == '28:2:an,19:5:array,8:of stuff,}]'
89
+ end
90
+
83
91
  end
84
92
 
85
93
 
@@ -63,11 +63,11 @@ describe Strelka::HTTPResponse::Negotiation do
63
63
  it "can provide blocks for bodies of several different mediatypes" do
64
64
  @req.headers.accept = 'application/x-yaml, application/json; q=0.7, text/xml; q=0.2'
65
65
 
66
- @res.for( 'application/json' ) { %{["a JSON dump"]} }
67
- @res.for( 'application/x-yaml' ) { "---\na: YAML dump\n\n" }
66
+ @res.for( 'application/json' ) { ["a JSON dump"] }
67
+ @res.for( 'application/x-yaml' ) { { 'a' => "YAML dump" } }
68
68
 
69
69
  @res.negotiated_body.rewind
70
- @res.negotiated_body.read.should == "---\na: YAML dump\n\n"
70
+ @res.negotiated_body.read.should == "---\na: YAML dump\n"
71
71
  @res.content_type.should == "application/x-yaml"
72
72
  @res.header_data.should =~ /accept(?!-)/i
73
73
  end
@@ -100,6 +100,12 @@ describe Strelka::HTTPResponse::Negotiation do
100
100
  @res.header_data.should =~ /accept(?!-)/i
101
101
  end
102
102
 
103
+ it "raises an exception if given a block for an unknown symbolic mediatype" do
104
+ expect {
105
+ @res.for( :yaquil ) {}
106
+ }.to raise_error( StandardError, /no known mimetype/i )
107
+ end
108
+
103
109
  end
104
110
 
105
111
 
@@ -132,7 +138,7 @@ describe Strelka::HTTPResponse::Negotiation do
132
138
  @res.body = File.open( __FILE__, 'r:iso-8859-5' )
133
139
  @res.content_type = 'text/plain'
134
140
 
135
- @res.negotiated_body.encoding.should == Encoding::KOI8_R
141
+ @res.negotiated_body.read.encoding.should == Encoding::KOI8_R
136
142
  @res.header_data.should =~ /accept-charset(?!-)/i
137
143
  end
138
144
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strelka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0.pre.393
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -30,7 +30,7 @@ cert_chain:
30
30
  6mKCwjpegytE0oifXfF8k75A9105cBnNiMZOe1tXiqYc/exCgWvbggurzDOcRkZu
31
31
  /YSusaiDXHKU2O3Akc3htA==
32
32
  -----END CERTIFICATE-----
33
- date: 2013-03-26 00:00:00.000000000 Z
33
+ date: 2013-05-02 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: configurability
@@ -122,14 +122,14 @@ dependencies:
122
122
  requirements:
123
123
  - - ~>
124
124
  - !ruby/object:Gem::Version
125
- version: '0.0'
125
+ version: '0.2'
126
126
  type: :runtime
127
127
  prerelease: false
128
128
  version_requirements: !ruby/object:Gem::Requirement
129
129
  requirements:
130
130
  - - ~>
131
131
  - !ruby/object:Gem::Version
132
- version: '0.0'
132
+ version: '0.2'
133
133
  - !ruby/object:Gem::Dependency
134
134
  name: sysexits
135
135
  requirement: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file