thingfish 0.5.0.pre20160707192835 → 0.5.0.pre20161103181816

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1cb359c51a202a06ce18845971fb239473b3b52f
4
- data.tar.gz: 771be1e193d9d560f0669b8f5b2718684c673e70
3
+ metadata.gz: 74a092349d627e3de7578603e6cbba04c29f8045
4
+ data.tar.gz: eb4868b63ef6b8ad8b95c4ff5954f4482924bb3d
5
5
  SHA512:
6
- metadata.gz: 407d223a9dd672b39cea0e0d98222710835e65525d5e2011f5964a39cd1a9a3c58ab4aecea83ac591219ef9277be8a481179fc82fe825b6572ecc762fffe3991
7
- data.tar.gz: 4d58598b60d541b5e9deeeb1a7e06498c55e7828b8543f4baa0438c1a6b236ea61a993e2e041d5b4eb2a659463c15d7d081f16c99751b0650fa96bac186ee5ac
6
+ metadata.gz: 6e3a206fa9f2ad2dd07543f407f85972a42b4f073ae8cc3eab66ead4ec5947b74c6f4228741a96efdb15a22101c4251cc49cee7a6e4b5720a1bf5acefda41967
7
+ data.tar.gz: a923141975987b85e96e84bd20c017d06609110abf10e319bd76a61ef51be1f0b6e59e2c66d8bc5d3d4d0275c862d8a3826b2e6c17f844daf456d6b7cfb21d91
checksums.yaml.gz.sig ADDED
Binary file
data.tar.gz.sig ADDED
Binary file
data/Manifest.txt CHANGED
@@ -1,4 +1,6 @@
1
1
  .simplecov
2
+ ChangeLog
3
+ Gemfile
2
4
  History.rdoc
3
5
  LICENSE
4
6
  Manifest.txt
@@ -7,6 +9,7 @@ README.rdoc
7
9
  Rakefile
8
10
  bin/tfprocessord
9
11
  bin/thingfish
12
+ etc/mongrel2-config.rb
10
13
  etc/thingfish.conf.example
11
14
  lib/strelka/app/metadata.rb
12
15
  lib/strelka/httprequest/metadata.rb
@@ -20,6 +23,7 @@ lib/thingfish/metastore/memory.rb
20
23
  lib/thingfish/mixins.rb
21
24
  lib/thingfish/processor.rb
22
25
  lib/thingfish/processor/mp3.rb
26
+ lib/thingfish/processor/sha256.rb
23
27
  lib/thingfish/processordaemon.rb
24
28
  lib/thingfish/spechelpers.rb
25
29
  spec/data/APIC-1-image.mp3
@@ -35,5 +39,6 @@ spec/thingfish/metastore/memory_spec.rb
35
39
  spec/thingfish/metastore_spec.rb
36
40
  spec/thingfish/mixins_spec.rb
37
41
  spec/thingfish/processor/mp3_spec.rb
42
+ spec/thingfish/processor/sha256_spec.rb
38
43
  spec/thingfish/processor_spec.rb
39
44
  spec/thingfish_spec.rb
@@ -230,6 +230,7 @@ class Thingfish::Handler < Strelka::App
230
230
  :datastore => self.datastore.class.name
231
231
  }
232
232
 
233
+ self.check_resource_permissions( req )
233
234
  res.for( :text, :json, :yaml ) { info }
234
235
  return res
235
236
  end
@@ -244,6 +245,8 @@ class Thingfish::Handler < Strelka::App
244
245
  get do |req|
245
246
  finish_with HTTP::BAD_REQUEST, req.params.error_messages.join(', ') unless req.params.okay?
246
247
 
248
+ self.check_resource_permissions( req )
249
+
247
250
  uuids = self.metastore.search( req.params.valid )
248
251
  self.log.debug "UUIDs are: %p" % [ uuids ]
249
252
 
@@ -340,13 +343,15 @@ class Thingfish::Handler < Strelka::App
340
343
  metadata = self.metastore.fetch( uuid )
341
344
 
342
345
  finish_with HTTP::NOT_FOUND, "No such object." unless object && metadata
346
+ self.check_resource_permissions( req, nil, metadata )
343
347
 
344
348
  res = req.response
345
349
  res.content_type = metadata['format']
346
350
 
351
+ self.add_etag_headers( req, metadata )
352
+
347
353
  if object.respond_to?( :path )
348
354
  path = Pathname( object.path )
349
- self.log.debug "Server is chrooted to: %p" % [ req.server_chroot ]
350
355
  chroot_path = path.relative_path_from( req.server_chroot )
351
356
  res.extend_reply_with( :sendfile )
352
357
  res.headers.content_length = object.size
@@ -387,6 +392,7 @@ class Thingfish::Handler < Strelka::App
387
392
  self.datastore.include?( uuid ) or
388
393
  finish_with HTTP::NOT_FOUND, "No such object."
389
394
 
395
+ self.check_resource_permissions( req, uuid )
390
396
  self.remove_related_resources( uuid )
391
397
  self.save_resource( req, uuid )
392
398
  self.send_event( :replaced, :uuid => uuid )
@@ -403,6 +409,8 @@ class Thingfish::Handler < Strelka::App
403
409
  delete ':uuid' do |req|
404
410
  uuid = req.params[:uuid]
405
411
 
412
+ self.check_resource_permissions( req, uuid )
413
+
406
414
  self.datastore.remove( uuid ) or finish_with( HTTP::NOT_FOUND, "No such object." )
407
415
  metadata = self.metastore.remove( uuid )
408
416
  self.remove_related_resources( uuid )
@@ -433,9 +441,13 @@ class Thingfish::Handler < Strelka::App
433
441
 
434
442
  finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
435
443
 
444
+ metadata = self.metastore.fetch( uuid )
445
+ metadata[ 'oid' ] = uuid
446
+ self.check_resource_permissions( req, uuid, metadata )
447
+
436
448
  res = req.response
437
449
  res.status = HTTP::OK
438
- res.for( :json, :yaml ) { self.metastore.fetch( uuid ) }
450
+ res.for( :json, :yaml ) { metadata }
439
451
 
440
452
  return res
441
453
  end
@@ -449,9 +461,12 @@ class Thingfish::Handler < Strelka::App
449
461
 
450
462
  finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
451
463
 
464
+ metadata = self.metastore.fetch( uuid )
465
+ self.check_resource_permissions( req, uuid, metadata )
466
+
452
467
  res = req.response
453
468
  res.status = HTTP::OK
454
- res.for( :json, :yaml ) { self.metastore.fetch_value( uuid, key ) }
469
+ res.for( :json, :yaml ) { metadata[key] }
455
470
 
456
471
  return res
457
472
  end
@@ -467,6 +482,9 @@ class Thingfish::Handler < Strelka::App
467
482
  finish_with( HTTP::CONFLICT, "Key already exists." ) unless
468
483
  self.metastore.fetch_value( uuid, key ).nil?
469
484
 
485
+ metadata = self.metastore.fetch( uuid )
486
+ self.check_resource_permissions( req, uuid, metadata )
487
+
470
488
  self.metastore.merge( uuid, key => req.body.read )
471
489
  self.send_event( :metadata_updated, :uuid => uuid, :key => key )
472
490
 
@@ -490,6 +508,9 @@ class Thingfish::Handler < Strelka::App
490
508
  finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
491
509
  previous_value = self.metastore.fetch( uuid, key )
492
510
 
511
+ metadata = self.metastore.fetch( uuid )
512
+ self.check_resource_permissions( req, uuid, metadata )
513
+
493
514
  self.metastore.merge( uuid, key => req.body.read )
494
515
  self.send_event( :metadata_replaced, :uuid => uuid, :key => key )
495
516
 
@@ -514,6 +535,9 @@ class Thingfish::Handler < Strelka::App
514
535
 
515
536
  finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
516
537
 
538
+ metadata = self.metastore.fetch( uuid )
539
+ self.check_resource_permissions( req, uuid, metadata )
540
+
517
541
  op_metadata = self.metastore.fetch( uuid, *OPERATIONAL_METADATA_KEYS )
518
542
  new_metadata = self.extract_metadata( req )
519
543
  self.metastore.save( uuid, new_metadata.merge(op_metadata) )
@@ -533,6 +557,9 @@ class Thingfish::Handler < Strelka::App
533
557
 
534
558
  finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
535
559
 
560
+ metadata = self.metastore.fetch( uuid )
561
+ self.check_resource_permissions( req, uuid, metadata )
562
+
536
563
  new_metadata = self.extract_metadata( req )
537
564
  self.metastore.merge( uuid, new_metadata )
538
565
  self.send_event( :metadata_updated, :uuid => uuid )
@@ -551,6 +578,9 @@ class Thingfish::Handler < Strelka::App
551
578
 
552
579
  finish_with( HTTP::NOT_FOUND, "No such object." ) unless self.metastore.include?( uuid )
553
580
 
581
+ metadata = self.metastore.fetch( uuid )
582
+ self.check_resource_permissions( req, uuid, metadata )
583
+
554
584
  self.metastore.remove_except( uuid, *OPERATIONAL_METADATA_KEYS )
555
585
  self.send_event( :metadata_deleted, :uuid => uuid )
556
586
 
@@ -571,6 +601,9 @@ class Thingfish::Handler < Strelka::App
571
601
  finish_with( HTTP::FORBIDDEN, "Protected metadata." ) if
572
602
  OPERATIONAL_METADATA_KEYS.include?( key )
573
603
 
604
+ metadata = self.metastore.fetch( uuid )
605
+ self.check_resource_permissions( req, uuid, metadata )
606
+
574
607
  self.metastore.remove( uuid, key )
575
608
  self.send_event( :metadata_deleted, :uuid => uuid, :key => key )
576
609
 
@@ -593,6 +626,9 @@ class Thingfish::Handler < Strelka::App
593
626
  metadata.merge!( self.extract_header_metadata(request) )
594
627
  metadata.merge!( self.extract_default_metadata(request) )
595
628
 
629
+ self.verify_operational_metadata( metadata )
630
+ self.check_resource_permissions( request, uuid, metadata )
631
+
596
632
  if uuid
597
633
  self.log.info "Replacing resource %s (encoding: %p)" %
598
634
  [ uuid, request.headers.content_encoding ]
@@ -714,6 +750,15 @@ class Thingfish::Handler < Strelka::App
714
750
  end
715
751
 
716
752
 
753
+ ### Check that the metadata provided contains valid values for
754
+ ### the operational keys, before saving a resource to disk.
755
+ def verify_operational_metadata( metadata )
756
+ if metadata.values_at( *OPERATIONAL_METADATA_KEYS ).any?( &:nil? )
757
+ finish_with( HTTP::BAD_REQUEST, "Missing operational attribute." )
758
+ end
759
+ end
760
+
761
+
717
762
  ### Send an event of +type+ with the given +msg+ over the zmq event socket.
718
763
  def send_event( type, msg )
719
764
  esock = self.event_socket or return
@@ -723,6 +768,30 @@ class Thingfish::Handler < Strelka::App
723
768
  end
724
769
 
725
770
 
771
+ ### Add browser cache headers for resources. This requires the sha256
772
+ ### processor plugin to be enabled for stored resources.
773
+ def add_etag_headers( request, metadata )
774
+ response = request.response
775
+ checksum = metadata[ 'checksum' ]
776
+ return unless checksum
777
+
778
+ if (( match = request.headers[ :if_none_match ] ))
779
+ match = match.gsub( '"', '' ).split( /,\s*/ )
780
+ finish_with( HTTP::NOT_MODIFIED ) if match.include?( checksum )
781
+ end
782
+
783
+ response.headers[ :etag ] = checksum
784
+ return
785
+ end
786
+
787
+
788
+ ### Supply a method that child handlers can override. The regular auth
789
+ ### plugin runs too early (but can also be used), this hook allows
790
+ ### child handlers to make access decisions based on the +request+
791
+ ### object, +uuid+ of the resource, or +metadata+ of the fetched resource.
792
+ def check_resource_permissions( request, uuid=nil, metadata=nil ); end
793
+
794
+
726
795
  end # class Thingfish::Handler
727
796
 
728
797
  # vim: set nosta noet ts=4 sw=4:
@@ -70,7 +70,9 @@ describe Thingfish::Handler do
70
70
 
71
71
 
72
72
  it 'accepts a POSTed upload' do
73
- req = factory.post( '/', TEST_TEXT_DATA, content_type: 'text/plain' )
73
+ req = factory.post( '/', TEST_TEXT_DATA )
74
+ req.content_type = 'text/plain'
75
+ req.headers.content_length = TEST_TEXT_DATA.bytesize
74
76
  res = @handler.handle( req )
75
77
 
76
78
  expect( res.status_line ).to match( /201 created/i )
@@ -145,6 +147,17 @@ describe Thingfish::Handler do
145
147
  end
146
148
 
147
149
 
150
+ it 'returns a BAD_REQUEST if unable to extract operational metadata' do
151
+ req = factory.post( '/', TEST_TEXT_DATA )
152
+ req.content_type = 'text/plain'
153
+
154
+ res = @handler.handle( req )
155
+ res.body.rewind
156
+ expect( res.status ).to be( HTTP::BAD_REQUEST )
157
+ expect( res.body.read ).to match( /missing operational attribute/i )
158
+ end
159
+
160
+
148
161
  it "allows additional metadata to be attached to uploads via X-Thingfish-* headers" do
149
162
  headers = {
150
163
  content_type: 'text/plain',
@@ -152,6 +165,7 @@ describe Thingfish::Handler do
152
165
  x_thingfish_tags: 'rapper,ukraine,potap',
153
166
  }
154
167
  req = factory.post( '/', TEST_TEXT_DATA, headers )
168
+ req.headers.content_length = TEST_TEXT_DATA.bytesize
155
169
  res = @handler.handle( req )
156
170
 
157
171
  expect( res.status_line ).to match( /201 created/i )
@@ -169,6 +183,7 @@ describe Thingfish::Handler do
169
183
  @handler.metastore.save( uuid, {'format' => 'text/plain'} )
170
184
 
171
185
  req = factory.put( "/#{uuid}", @png_io, content_type: 'image/png' )
186
+ req.headers.content_length = @png_io.read.bytesize
172
187
  res = @handler.handle( req )
173
188
 
174
189
  expect( res.status ).to eq( HTTP::NO_CONTENT )
@@ -182,6 +197,7 @@ describe Thingfish::Handler do
182
197
  @handler.metastore.save( uuid, {'format' => 'text/plain'} )
183
198
 
184
199
  req = factory.put( "/#{uuid.upcase}", @png_io, content_type: 'image/png' )
200
+ req.headers.content_length = @png_io.read.bytesize
185
201
  res = @handler.handle( req )
186
202
 
187
203
  expect( res.status ).to eq( HTTP::NO_CONTENT )
@@ -339,6 +355,32 @@ describe Thingfish::Handler do
339
355
  end
340
356
 
341
357
 
358
+ it "adds browser cache headers to resources with a checksum attribute" do
359
+ uuid = @handler.datastore.save( @png_io )
360
+ @handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' )
361
+
362
+ req = factory.get( "/#{uuid}" )
363
+ result = @handler.handle( req )
364
+
365
+ expect( result.status_line ).to match( /200 ok/i )
366
+ expect( result.headers.etag ).to eq( '123456' )
367
+ end
368
+
369
+
370
+ it "returns a 304 not modified for unchanged client cache requests" do
371
+ uuid = @handler.datastore.save( @png_io )
372
+ @handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' )
373
+
374
+ req = factory.get( "/#{uuid}" )
375
+ req.headers[ :if_none_match ] = '123456'
376
+ result = @handler.handle( req )
377
+
378
+ expect( result.status_line ).to match( /304 not modified/i )
379
+ expect( result.body.read ).to be_empty
380
+ end
381
+
382
+
383
+
342
384
  it "can remove everything associated with an object id" do
343
385
  uuid = @handler.datastore.save( @png_io )
344
386
  @handler.metastore.save( uuid, {
@@ -391,6 +433,7 @@ describe Thingfish::Handler do
391
433
  expect( result.status ).to eq( 200 )
392
434
  expect( result.headers.content_type ).to eq( 'application/json' )
393
435
  expect( content_hash ).to be_a( Hash )
436
+ expect( content_hash['oid'] ).to eq( uuid )
394
437
  expect( content_hash['extent'] ).to eq( 288 )
395
438
  expect( content_hash['created'] ).to eq( Time.at(1378313840).to_s )
396
439
  end
@@ -733,6 +776,7 @@ describe Thingfish::Handler do
733
776
  described_class.configure( :processors => %w[test] )
734
777
 
735
778
  req = factory.post( '/', TEST_TEXT_DATA, content_type: 'text/plain' )
779
+ req.headers.content_length = TEST_TEXT_DATA.bytesize
736
780
  res = @handler.handle( req )
737
781
  uuid = res.headers.x_thingfish_uuid
738
782
 
@@ -816,6 +860,7 @@ describe Thingfish::Handler do
816
860
 
817
861
  it "publishes notifications about uploaded assets to a PUBSUB socket" do
818
862
  req = factory.post( '/', TEST_TEXT_DATA, content_type: 'text/plain' )
863
+ req.headers.content_length = TEST_TEXT_DATA.bytesize
819
864
  res = @handler.handle( req )
820
865
 
821
866
  handles = ZMQ.select( [@subsock], nil, nil, 0 )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thingfish
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0.pre20160707192835
4
+ version: 0.5.0.pre20161103181816
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -11,26 +11,32 @@ bindir: bin
11
11
  cert_chain:
12
12
  - |
13
13
  -----BEGIN CERTIFICATE-----
14
- MIIDMDCCAhigAwIBAgIBAjANBgkqhkiG9w0BAQUFADA+MQwwCgYDVQQDDANnZWQx
14
+ MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MQwwCgYDVQQDDANnZWQx
15
15
  GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
16
- HhcNMTYwNjAyMDE1NTQ2WhcNMTcwNjAyMDE1NTQ2WjA+MQwwCgYDVQQDDANnZWQx
16
+ HhcNMTYwODIwMTgxNzQyWhcNMTcwODIwMTgxNzQyWjA+MQwwCgYDVQQDDANnZWQx
17
17
  GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
18
- ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDb92mkyYwuGBg1oRxt2tkH
19
- +Uo3LAsaL/APBfSLzy8o3+B3AUHKCjMUaVeBoZdWtMHB75X3VQlvXfZMyBxj59Vo
20
- cDthr3zdao4HnyrzAIQf7BO5Y8KBwVD+yyXCD/N65TTwqsQnO3ie7U5/9ut1rnNr
21
- OkOzAscMwkfQxBkXDzjvAWa6UF4c5c9kR/T79iA21kDx9+bUMentU59aCJtUcbxa
22
- 7kcKJhPEYsk4OdxR9q2dphNMFDQsIdRO8rywX5FRHvcb+qnXC17RvxLHtOjysPtp
23
- EWsYoZMxyCDJpUqbwoeiM+tAHoz2ABMv3Ahie3Qeb6+MZNAtMmaWfBx3dg2u+/WN
24
- AgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSZ0hCV
25
- qoHr122fGKelqffzEQBhszANBgkqhkiG9w0BAQUFAAOCAQEAF2XCzjfTFxkcVvuj
26
- hhBezFkZnMDYtWezg4QCkR0RHg4sl1LdXjpvvI59SIgD/evD1hOteGKsXqD8t0E4
27
- OPAWWv/z+JRma72zeYsBZLSDRPIUvBoul6qCpvY0MiWTh496mFwOxT5lvSAUoh+U
28
- pQ/MQeH/yC6hbGp7IYska6J8T4z5XkYqafYZ3eKQ8H+xPd/z+gYx+jd0PfkWf1Wk
29
- QQdziL01SKBHf33OAH/p/puCpwS+ZDfgnNx5oMijWbc671UXkrt7zjD0kGakq+9I
30
- hnfm736z8j1wvWddqf45++gwPpDr1E4zoAq2PgRl/WBNyR0hfoZLpi3TnHu3eC0x
31
- uALKNA==
18
+ ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC/JWGRHO+USzR97vXjkFgt
19
+ 83qeNf2KHkcvrRTSnR64i6um/ziin0I0oX23H7VYrDJC9A/uoUa5nGRJS5Zw/+wW
20
+ ENcvWVZS4iUzi4dsYJGY6yEOsXh2CcF46+QevV8iE+UmbkU75V7Dy1JCaUOyizEt
21
+ TH5UHsOtUU7k9TYARt/TgYZKuaoAMZZd5qyVqhF1vV+7/Qzmp89NGflXf2xYP26a
22
+ 4MAX2qqKX/FKXqmFO+AGsbwYTEds1mksBF3fGsFgsQWxftG8GfZQ9+Cyu2+l1eOw
23
+ cZ+lPcg834G9DrqW2zhqUoLr1MTly4pqxYGb7XoDhoR7dd1kFE2a067+DzWC/ADt
24
+ +QkcqWUm5oh1fN0eqr7NsZlVJDulFgdiiYPQiIN7UNsii4Wc9aZqBoGcYfBeQNPZ
25
+ soo/6za/bWajOKUmDhpqvaiRv9EDpVLzuj53uDoukMMwxCMfgb04+ckQ0t2G7wqc
26
+ /D+K9JW9DDs3Yjgv9k4h7YMhW5gftosd+NkNC/+Y2CkCAwEAAaN1MHMwCQYDVR0T
27
+ BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFHKN/nkRusdqCJEuq3lgB3fJvyTg
28
+ MBwGA1UdEQQVMBOBEWdlZEBGYWVyaWVNVUQub3JnMBwGA1UdEgQVMBOBEWdlZEBG
29
+ YWVyaWVNVUQub3JnMA0GCSqGSIb3DQEBCwUAA4IBgQAPJzKiT0zBU7kpqe0aS2qb
30
+ FI0PJ4y5I8buU4IZGUD5NEt/N7pZNfOyBxkrZkXhS44Fp+xwBH5ebLbq/WY78Bqd
31
+ db0z6ZgW4LMYMpWFfbXsRbd9TU2f52L8oMAhxOvF7Of5qJMVWuFQ8FPagk2iHrdH
32
+ inYLQagqAF6goWTXgAJCdPd6SNeeSNqA6vlY7CV1Jh5kfNJJ6xu/CVij1GzCLu/5
33
+ DMOr26DBv+qLJRRC/2h34uX71q5QgeOyxvMg+7V3u/Q06DXyQ2VgeeqiwDFFpEH0
34
+ PFkdPO6ZqbTRcLfNH7mFgCBJjsfSjJrn0sPBlYyOXgCoByfZnZyrIMH/UY+lgQqS
35
+ 6Von1VDsfQm0eJh5zYZD64ZF86phSR7mUX3mXItwH04HrZwkWpvgd871DZVR3i1n
36
+ w8aNA5re5+Rt/Vvjxj5AcEnZnZiz5x959NaddQocX32Z1unHw44pzRNUur1GInfW
37
+ p4vpx2kUSFSAGjtCbDGTNV2AH8w9OU4xEmNz8c5lyoA=
32
38
  -----END CERTIFICATE-----
33
- date: 2016-07-08 00:00:00.000000000 Z
39
+ date: 2016-11-04 00:00:00.000000000 Z
34
40
  dependencies:
35
41
  - !ruby/object:Gem::Dependency
36
42
  name: strelka
@@ -103,47 +109,47 @@ dependencies:
103
109
  - !ruby/object:Gem::Version
104
110
  version: '0.2'
105
111
  - !ruby/object:Gem::Dependency
106
- name: rdoc
112
+ name: simplecov
107
113
  requirement: !ruby/object:Gem::Requirement
108
114
  requirements:
109
115
  - - "~>"
110
116
  - !ruby/object:Gem::Version
111
- version: '4.0'
117
+ version: '0.7'
112
118
  type: :development
113
119
  prerelease: false
114
120
  version_requirements: !ruby/object:Gem::Requirement
115
121
  requirements:
116
122
  - - "~>"
117
123
  - !ruby/object:Gem::Version
118
- version: '4.0'
124
+ version: '0.7'
119
125
  - !ruby/object:Gem::Dependency
120
- name: simplecov
126
+ name: ruby-mp3info
121
127
  requirement: !ruby/object:Gem::Requirement
122
128
  requirements:
123
129
  - - "~>"
124
130
  - !ruby/object:Gem::Version
125
- version: '0.7'
131
+ version: '0.8'
126
132
  type: :development
127
133
  prerelease: false
128
134
  version_requirements: !ruby/object:Gem::Requirement
129
135
  requirements:
130
136
  - - "~>"
131
137
  - !ruby/object:Gem::Version
132
- version: '0.7'
138
+ version: '0.8'
133
139
  - !ruby/object:Gem::Dependency
134
- name: ruby-mp3info
140
+ name: rdoc
135
141
  requirement: !ruby/object:Gem::Requirement
136
142
  requirements:
137
143
  - - "~>"
138
144
  - !ruby/object:Gem::Version
139
- version: '0.8'
145
+ version: '4.0'
140
146
  type: :development
141
147
  prerelease: false
142
148
  version_requirements: !ruby/object:Gem::Requirement
143
149
  requirements:
144
150
  - - "~>"
145
151
  - !ruby/object:Gem::Version
146
- version: '0.8'
152
+ version: '4.0'
147
153
  - !ruby/object:Gem::Dependency
148
154
  name: hoe
149
155
  requirement: !ruby/object:Gem::Requirement
@@ -237,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
237
243
  version: 1.3.1
238
244
  requirements: []
239
245
  rubyforge_project:
240
- rubygems_version: 2.4.8
246
+ rubygems_version: 2.5.1
241
247
  signing_key:
242
248
  specification_version: 4
243
249
  summary: Thingfish is a extensible, web-based digital asset manager
metadata.gz.sig ADDED
Binary file