streams 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/streams.rb +3 -1100
  2. data/lib/streams/activitystreams.rb +1106 -0
  3. metadata +2 -1
@@ -4,1104 +4,7 @@
4
4
  # #
5
5
  # A simple Activity Streams implementation. #
6
6
  # (forgive me... my ruby's a bit rusty) #
7
- # #
8
- # example use: #
9
- # require 'activitystreams' #
10
- # include ActivityStreams #
11
- # #
12
- # STDOUT << activity { #
13
- # verb :post #
14
- # actor person { #
15
- # display_name 'James' #
16
- # } #
17
- # object note { #
18
- # content 'This is a test' #
19
- # } #
20
- # } #
21
- # #
22
7
  ##############################################
23
-
24
- require 'json'
25
- require "time"
26
- require 'addressable/uri'
27
- require 'base64'
28
- require 'zlib'
29
- require 'i18n'
30
- require 'mime/types'
31
-
32
- class Hash
33
- # allows a Hash to be used in place of an
34
- # ASObj ... we don't necessarily want a
35
- # mixin on this, so just set a property
36
- def __object_type= ot
37
- @object_type = ot
38
- end
39
-
40
- def __object_type
41
- @object_type
42
- end
43
-
44
- end
45
-
46
- class Object
47
-
48
- # Tests whether the method exists. Unlike the std method, however,
49
- # does not throw a NameError if it doesn't. Just returns false
50
- def method? sym
51
- method sym rescue false
52
- end
53
-
54
- # Tests to see if the Object is one of several possible types
55
- # like is_a? but accepting multiple arguments
56
- def one_of_type? *args
57
- args.any? {|x| is_a? x}
58
- end
59
-
60
- end
61
-
62
- module ActivityStreams
63
-
64
- # Provides a number of generally useful utilities methods
65
- module Matchers
66
- include Addressable
67
-
68
- # true if m validates as a isegment-nz-nc as defined by RFC 3987.
69
- # The activity streams spec requires that verbs and object types
70
- # MUST either be isegment-nz-nc or absolute IRI productions.
71
- def is_token? m
72
- return false if m == nil
73
- m = m.to_s
74
- (m =~ /^([a-zA-Z0-9\-\.\_\~]|\%[0-9a-fA-F]{2}|[\!\$\&\'\(\)\*\+\,\;\=\@])+$/) != nil
75
- end
76
-
77
- # true if m is parseable as an IRI and is absolute
78
- def is_absolute_iri? m
79
- URI.parse(m).absolute? rescue false
80
- end
81
-
82
- # true if m is a valid verb
83
- def is_verb? m
84
- is_token?(m) || is_absolute_iri?(m)
85
- end
86
-
87
- # true if m is a valid MIME Media Type
88
- def is_mime_type? m
89
- MIME::Type.new m rescue false
90
- end
91
-
92
- # true if m is a valid RFC 4646 Lang tag
93
- def is_lang_tag? m
94
- I18n::Locale::Tag::Rfc4646.tag m rescue false
95
- end
96
-
97
- # utility method providing the basic structure of validation
98
- # checkers for the various fields...
99
- def checker &block
100
- ->(v) do
101
- raise ArgumentError unless block.call v
102
- v
103
- end
104
- end
105
-
106
- module_function :checker, :is_token?, :is_verb?, :is_absolute_iri?, :is_mime_type?, :is_lang_tag?
107
-
108
- end
109
-
110
- # Defines the basic functions for the Activity Streams DSL
111
- module Makers
112
-
113
- # Create a new object by copying another.
114
- # A list of properties to omit from the new
115
- # copy can be provided a variable arguments.
116
- # For instance, if you have an existing activity
117
- # object and wish to copy everything but the
118
- # current verb and actor properties, you could
119
- # call new_act = copy_from(old_act, :verb, :actor) { ... }
120
- def copy_from(other,*without,&block)
121
- ASObj.from other,*without,&block
122
- end
123
-
124
- # Create a new Activity Streams Object
125
- def object(object_type=nil,&block)
126
- ASObj.generate object_type,&block
127
- end
128
-
129
- # Create a new Media Link
130
- def media_link &block
131
- ASObj.generate :media_link,true,&block
132
- end
133
-
134
- # Create a new Collection Object
135
- def collection include_object_type=false, &block
136
- ASObj.generate :collection, !include_object_type, &block
137
- end
138
-
139
- # Create a new Activity Object
140
- def activity include_object_type=false, &block
141
- ASObj.generate :activity, !include_object_type, &block
142
- end
143
-
144
- # Utility method for returning the current time
145
- def now
146
- Time.now.utc
147
- end
148
-
149
- # For the remain object types from the Activity Streams Schema
150
- # iterate through them and create a factory method for each
151
- [ :alert,
152
- :application,
153
- :article,
154
- :audio,
155
- :badge,
156
- :binary,
157
- :bookmark,
158
- :comment,
159
- :device,
160
- :event,
161
- :file,
162
- :game,
163
- :group,
164
- :image,
165
- :issue,
166
- :job,
167
- :note,
168
- :offer,
169
- :organization,
170
- :page,
171
- :permission,
172
- :person,
173
- :place,
174
- :process,
175
- :product,
176
- :question,
177
- :review,
178
- :role,
179
- :service,
180
- :task,
181
- :team,
182
- :video
183
- ].each {|o|
184
- module_eval "def #{o}(&block) object :#{o}, &block end"
185
- }
186
- end
187
-
188
- def checker &block
189
- Matchers.checker &block
190
- end
191
-
192
- module_function :checker
193
-
194
- include Makers, Matchers
195
-
196
- # Represents a basic Activity Streams Object...
197
- # Instances, once created, are immutable for
198
- # all the core properties. The object maintains
199
- # an internal hash and performs basic input
200
- # validation to ensure that the built object
201
- # conforms to the basic requirements of the
202
- # Activity Streams specifications. Specific
203
- # validation requirements are defined by the
204
- # Spec module associated with the object_type
205
- # specified for the ASObj instance
206
- class ASObj
207
- include Makers
208
-
209
- def initialize object_type=nil
210
- @_ = {}
211
- @_.__object_type = object_type
212
- @object_type = object_type
213
- extend SPECS[object_type] || SPECS[nil]
214
- strict
215
- end
216
-
217
- # Puts this ASObj into lenient validation mode
218
- def lenient
219
- @lenient = true
220
- end
221
-
222
- # Puts this ASObj into strict validation mode
223
- def strict
224
- @lenient = false
225
- end
226
-
227
- # Tells this ASObj to generate formatted JSON output
228
- def pretty
229
- @pretty = true
230
- end
231
-
232
- # true if this ASObj has been configured to generate formatted JSON output
233
- def pretty?
234
- @pretty || false
235
- end
236
-
237
- # true if this ASObj is operating in lenient mode
238
- def lenient?
239
- @lenient
240
- end
241
-
242
- # true if this ASObj is operating in strict mode
243
- def strict?
244
- !lenient?
245
- end
246
-
247
- # the internal object type identifier for this ASObj
248
- def __object_type
249
- @object_type
250
- end
251
-
252
- # return a frozen copy of the internal hash
253
- def finish
254
- @_.dup.freeze
255
- end
256
-
257
- # write this thing out, the param must repond to the << operator for appending
258
- def append_to out
259
- raise ArgumentError unless out.respond_to?:<<
260
- out << to_s
261
- end
262
- alias :>> append_to
263
-
264
- # force pretty printing
265
- def pretty_to out
266
- out << JSON.pretty_generate(@_)
267
- end
268
-
269
- # generates a copy of this object
270
- def copy_of *without, &block
271
- ASObj.from self, *without, &block
272
- end
273
-
274
- def to_s
275
- pretty? ? JSON.pretty_generate(@_) : @_.to_json
276
- end
277
-
278
- def [] k
279
- @_[send("alias_for_#{k}".to_sym) || k]
280
- end
281
- protected :[]
282
-
283
- # Sets a value on the internal hash without any type checking
284
- # if v is an instance of ASObj, finish will be called
285
- # to get the frozen hash ...
286
- def set k,v
287
- key = k.to_s.to_sym
288
- v = (v.is_a?(ASObj) ? v.finish : v) unless v == nil
289
- @_[key] = v unless v == nil
290
- @_.delete key if v == nil
291
- end
292
- alias :[]= :set
293
-
294
- def freeze
295
- @_.freeze
296
- super
297
- end
298
-
299
- # Within the generator, any method call that has exactly one
300
- # parameter will be turned into a member of the underlying hash
301
- def property m, *args, &block
302
-
303
- # Return nil if it's looking for an unknown alias_for_* method
304
- return nil if m =~ /^alias\_for\_.*/
305
-
306
- # Special magic... if an unknown ? method is called, it's treated
307
- # as a check against the internal hash to see if the given field
308
- # has been set. For instance, priority? will check to see if the
309
- # priority field has been set
310
- return @_.has_key?(m.to_s[0...-1].to_sym) if m =~ /.*\?/
311
-
312
- # Is it an unknown to_ method? e.g. to_ary ... if so, fall through to default
313
- if m =~ /^to\_.*/
314
- super
315
- return
316
- end
317
-
318
- # Once we get past the special cases, check to see if we have the
319
- # expected number of arguments.
320
- if !args.length.within?(1..2)
321
- raise NoMethodError
322
- return
323
- end
324
-
325
- # Now we start to figure out the exact value to set
326
- transform, alias_for, checker = [:transform_,:alias_for_,:check_].map {|x| "#{x}#{m}".to_sym }
327
-
328
- v = args[0]
329
-
330
- # First, if the value given is a ASObj, call finish on it
331
- v = (v.is_a?(ASObj) ? v.finish : v) unless v == nil
332
-
333
- # If it's an Enumerable, but not a Hash, convert to an Array using Map,
334
- # If each of the member items are ASObj's call finish.
335
- v = v.map {|i| i.is_a?(ASObj) ? i.finish : i } if v.is_a?(Enumerable) && !v.is_a?(Hash)
336
-
337
- # If the value is a Time object, let's make sure it's ISO 8601
338
- v = v.iso8601 if v.is_a? Time
339
-
340
- # Finally, do the object_type specific transform, if any
341
- # note, this could potentially undo the previous checks if
342
- # the transform provided by a given spec module isn't well
343
- # behaved. that's ok tho, we'll trust that it's doing the
344
- # right thing and just move on ... we're going to be validating
345
- # next anyway
346
- v = send transform, v if method? transform
347
-
348
- # Now let's do validation... unless lenient is set
349
- if !args[1] && strict?
350
- ok = method?(checker) ? send(checker,v) : missing_check(v)
351
- raise ArgumentError unless ok
352
- end
353
- m = send alias_for if method? alias_for
354
- @_[m] = v unless v == nil
355
- @_.delete m if v == nil
356
- end
357
- alias :method_missing :property
358
-
359
- end
360
-
361
- class << ASObj
362
-
363
- # Performs the actual work of creating an ASObj and executing
364
- # the associated block to build it up, then freezing the
365
- # ASObj before returning it
366
- def generate object_type=nil, do_not_set_object_type=false, &block
367
- m = ASObj.new object_type
368
- m[:objectType] = object_type unless do_not_set_object_type
369
- m.instance_eval &block unless not block_given?
370
- m.freeze
371
- end
372
-
373
- # Creates a new ASObj by copying from another one
374
- def from other, *without, &block
375
- raise ArgumentError unless other.one_of_type?(ASObj,Hash)
376
- m = ASObj.new other.__object_type
377
- m.pretty if other.pretty?
378
- m.lenient if other.lenient?
379
- other.finish.each_pair {|k,y| m[k] = y unless without.include? k }
380
- m.instance_eval &block unless not block_given?
381
- m.freeze
382
- end
383
-
384
- end
385
-
386
- # The base module for all Validation Spec Modules.. these
387
- # define the requirements for the various Activity Streams
388
- # object types
389
- module Spec
390
-
391
- # by default, allow all values if a specific check hasn't been provided
392
- # Spec modules can override this behavior by defining their own missing_check
393
- def missing_check v
394
- true
395
- end
396
-
397
- # Defines the various utility methods used to build Spec modules
398
- module Defs
399
-
400
- # Maps an input symbol to a property name in the hash
401
- def def_alias sym, name
402
- define_method("alias_for_#{sym}".to_sym) {
403
- name
404
- } if name
405
- module_function "alias_for_#{sym}".to_sym
406
- end
407
-
408
- # Defines the method for validating the value of a
409
- # specific property.
410
- def def_checker sym, &block
411
- sym = "check_#{sym}".to_sym
412
- define_method sym,&block
413
- module_function sym
414
- end
415
-
416
- # Defines a transform for the value of a specific property
417
- def def_transform sym, &block
418
- sym = "transform_#{sym}".to_sym
419
- if block_given?
420
- define_method sym,&block
421
- else
422
- define_method(sym) {|v|v} # just return self if no transform defined
423
- end
424
- module_function sym
425
- end
426
-
427
- # Mark def_alias, def_checker and def_transform as private
428
- # these should only be called from within the Defs module
429
- private :def_alias, :def_checker, :def_transform
430
-
431
- # Define a property as being an absolute IRI
432
- def def_absolute_iri sym, name=nil
433
- def_transform(sym) {|v|
434
- next nil if v == nil
435
- Addressable::URI.parse(v)
436
- }
437
- def_checker(sym) { |v|
438
- # v must be an absolute IRI
439
- !v || is_absolute_iri?(v)
440
- }
441
- def_alias sym, name if name
442
- end
443
-
444
- # Define a property as being an ISO 8601 DateTime
445
- def def_date_time sym, name=nil
446
- def_transform(sym) {|v|
447
- next v if v == nil || v.is_a?(Time)
448
- Time.parse(v.to_s) rescue v
449
- }
450
- def_checker(sym) { |v|
451
- # v must be parseable as a time
452
- next true if v == nil || v.is_a?(Time)
453
- Time.parse(v.to_s) rescue next false
454
- true
455
- }
456
- def_alias sym, name if name
457
- end
458
-
459
- # Define a property as being an IRI ... does not have to be absolute
460
- def def_iri sym, name=nil
461
- def_transform(sym) {|v|
462
- next nil if v == nill
463
- Addressable::URI.parse(v)}
464
- def_checker(sym) { |v|
465
- # v must be parseable as a URI
466
- !v || Addressable::URI.parse(v) rescue false
467
- }
468
- def_alias sym, name if name
469
- end
470
-
471
- # Define a property as being a string, an additional block
472
- # can be passed in to perform additional checking (e.g. regex matching, etc)
473
- def def_string sym, name=nil, &block
474
- def_transform(sym) {|v|
475
- next nil if v == nil
476
- v.to_s
477
- }
478
- def_checker(sym) { |v|
479
- # v will be converted to a string, then checked against the optional
480
- # block... if the block returns false, raise a validation error
481
- next true if v == nil
482
- next block.call(v.to_s) if block_given?
483
- true
484
- }
485
- def_alias sym, name if name
486
- end
487
-
488
- # Define a property as being an ASObj.
489
- def def_object sym, object_type=nil, name=nil
490
- def_transform(sym)
491
- def_checker(sym) { |v|
492
- next true if v == nil
493
- # v must be an instance of the given object_type
494
- if object_type
495
- next false if v.__object_type != object_type
496
- end
497
- # right now this is pretty strict... we only allow Hash or ASObj
498
- # instances to be passed. TODO: see if we can relax this to enable
499
- # more flexible duck typing ...
500
- v.one_of_type? Hash, ASObj
501
- }
502
- def_alias sym, name if name
503
- def_property(sym, object_type, name) if object_type
504
- end
505
-
506
- # Define a property as being an Array of ASObj's
507
- def def_object_array sym, object_type=nil, name=nil
508
- def_alias sym, name if name
509
- def_transform(sym) {|v|
510
- next nil if v == nil
511
- orig = self[sym]
512
- if v.is_a?(Array)
513
- next orig ? orig + v : v
514
- end
515
- orig ? orig << v : [v]
516
- }
517
- def_checker(sym) { |v|
518
- next true if v == nil
519
- # v must be either an array or enumerable and each item
520
- # must be either a Hash or ASObj that matches the given
521
- # object_type, if any
522
- next false unless (v.one_of_type?(Array, Enumerable) && !v.is_a?(Hash))
523
- v.each {|x|
524
- return false unless x.one_of_type? ASObj, Hash
525
- return false if (object_type && x.__object_type != object_type)
526
- }
527
- true
528
- }
529
- end
530
-
531
- # Define a property as being an Array of Strings, an additional
532
- # block can be passed to perform additional checking
533
- def def_string_array sym, name=nil, &block
534
- def_transform(sym) {|v|
535
- next nil if v == nil
536
- orig = self[sym]
537
- if v.one_of_type? Array, Enumerable
538
- add = v.map {|x| x.to_s}
539
- next orig ? orig + add : add
540
- end
541
- orig ? orig << v.to_s : [v.to_s]
542
- }
543
- def_checker(sym) { |v|
544
- next true if v == nil
545
- next false unless (v.one_of_type?(Array, Enumerable) && !v.is_a?(Hash))
546
- v.each {|x|
547
- return false unless block.call(x)
548
- } if block_given?
549
- true
550
- }
551
- def_alias sym, name if name
552
- end
553
-
554
- def def_boolean sym, name=nil
555
- def_transform(sym) {|v|
556
- next false if v == nil
557
- v ? true : false
558
- }
559
- def_checker(sym) { |v|
560
- v.one_of_type? TrueClass, FalseClass
561
- }
562
- def_alias sym, name if name
563
-
564
- module_eval %Q/def #{sym}() property(:'#{sym}', true) end/
565
- module_eval %Q/def not_#{sym}() property(:'#{sym}', false) end/
566
- end
567
-
568
- # Define a property as being a Numeric
569
- def def_numeric sym, name=nil, &block
570
- def_checker(sym) { |v|
571
- next true if v == nil
572
- return false unless v.is_a? Numeric
573
- if block_given?
574
- next false unless block.call v
575
- end
576
- true
577
- }
578
- def_alias sym, name if name
579
- end
580
-
581
- # Define a property as being a non-negative fixnum
582
- def def_non_negative_int sym, name=nil
583
- def_numeric(sym, name) {|v|
584
- next false unless (v.is_a?(Fixnum) && v >= 0)
585
- true
586
- }
587
- end
588
-
589
- # Define a property as being a float with a bounded range
590
- def def_bound_float sym, range, name=nil
591
- def_numeric(sym, name) {|v|
592
- next false if (range.respond_to?(:include?) && !range.include?(v))
593
- true
594
- }
595
- end
596
-
597
- def def_property sym, type=nil, name=nil
598
- sym = sym.to_s
599
- module_eval %Q/
600
- def #{sym} &block
601
- self[:#{name || sym}] = ASObj.generate(:#{type},true,&block)
602
- end
603
- /
604
- end
605
- private :def_property
606
- end
607
-
608
- # Ensure the the Defs module is included in all spec modules...
609
- extend Defs
610
- def self.included(other)
611
- other.extend Defs
612
- end
613
-
614
- end
615
-
616
- # The base spec for all ASObj's
617
- module ObjectSpec
618
- include Spec
619
- def_string :content
620
- def_string :display_name, :displayName
621
- def_string :object_type, :objectType
622
- def_string :summary
623
- def_string :aka, :alias
624
- def_date_time :updated
625
- def_date_time :published
626
- def_date_time :start_time, :'start-time'
627
- def_date_time :end_time, :'end-time'
628
- def_object :links, :links
629
- def_object :author
630
- def_object :img, :media_link, :image
631
- def_object :source
632
- def_object :location, :place
633
- def_object :mood, :mood
634
- def_bound_float :rating, 0.0..5.0
635
- def_absolute_iri :id
636
- def_iri :url
637
- def_object_array :attachments
638
- def_object_array :in_reply_to, nil, :inReplyTo
639
-
640
- check = ->(x){ is_absolute_iri? x }
641
- def_string_array :downstream_duplicates, :downstreamDuplicates, &check
642
- def_string_array :upstream_duplicates, :upstreamDuplicates, &check
643
-
644
- def attachment m, &block
645
- property :attachments, m, &block
646
- end
647
-
648
- def downstream_duplicate m, &block
649
- property :downstream_duplicates, m, &block
650
- end
651
-
652
- def upstream_duplicate m, &block
653
- property :upstream_duplicates, m, &block
654
- end
655
-
656
- # Basic support for external vocabularies..
657
- # Developers will have to register their own
658
- # spec modules for these, but we at least
659
- # provide the constructor methods
660
- def ext_vocab sym, &block
661
- self[sym] = ASObj.generate(sym,true,&block)
662
- end
663
- [:schema_org, :ld, :dc, :odata, :opengraph].each do |x|
664
- module_eval "def #{x}(&block) ext_vocab(:#{x},&block) end"
665
- end
666
-
667
- # ensure that all spec object include the Defs module...
668
- include Defs
669
- def self.included(other)
670
- other.extend Defs
671
- other.module_exec {
672
- def self.included(o)
673
- o.extend Defs
674
- end
675
- }
676
- end
677
-
678
- end
679
-
680
- module ActivitySpec
681
- include ObjectSpec
682
- def_string :verb do |v| is_verb? v end
683
- def_string :content
684
- def_string :title
685
- def_object :icon, :media_link
686
- def_object :generator
687
- def_object :actor
688
- def_object :target
689
- def_object :obj, nil, :object
690
- def_object :provider
691
- def_object :context
692
- def_object :result
693
- def_object_array :to
694
- def_object_array :cc
695
- def_object_array :bto
696
- def_object_array :bcc
697
- def_bound_float :priority, 0.0..1.0
698
- end
699
-
700
- module MediaLinkSpec
701
- include Spec
702
- def_absolute_iri :url
703
- def_non_negative_int :duration
704
- def_non_negative_int :width
705
- def_non_negative_int :height
706
- end
707
-
708
- module MoodSpec
709
- include Spec
710
- def_string :display_name, :displayName
711
- def_object :img, :mediaLink, :image
712
- end
713
-
714
- module AddressSpec
715
- include Spec
716
- def_string :formatted
717
- def_string :street_address, :streetAddress
718
- def_string :locality
719
- def_string :region
720
- def_string :postal_code, :postalCode
721
- def_string :country
722
- end
723
-
724
- module PositionSpec
725
- include Spec
726
- def_numeric :altitude
727
- def_bound_float :longitude, -180.00..180.00
728
- def_bound_float :latitude, -90.00..90.00
729
- end
730
-
731
- module PlaceSpec
732
- include ObjectSpec
733
- def_object :position, :position
734
- def_object :address, :address
735
- end
736
-
737
- module CollectionSpec
738
- include ObjectSpec
739
- def_date_time :items_after, :itemsAfter
740
- def_date_time :items_before, :itemsBefore
741
- def_non_negative_int :items_per_page, :itemsPerPage
742
- def_non_negative_int :start_index, :startIndex
743
- def_non_negative_int :total_items, :totalItems
744
- def_object_array :items
745
- def_string_array :object_types, :objectTypes
746
-
747
- def item m, &block
748
- property :items, m, &block
749
- end
750
-
751
- end
752
-
753
- module AVSpec
754
- include ObjectSpec
755
- def_string :embed_code, :embedCode
756
- def_object :stream, :media_link
757
- end
758
-
759
- module FileSpec
760
- include ObjectSpec
761
- def_string :mime_type, :mimeType do |x| is_mime_type? x end
762
- def_string :md5
763
- def_absolute_iri :file_url, :fileUrl
764
- end
765
-
766
- module BinarySpec
767
- include FileSpec
768
- def_string :compression
769
- def_string :data
770
- def_non_negative_int :length
771
-
772
- def init_hasher hash
773
- require 'Digest'
774
- hash_name = "#{hash.to_s.upcase}"
775
- Digest.module_eval "#{hash_name}.new"
776
- rescue LoadError
777
- raise ArgumentError.new("Invalid Hash [#{hash}]")
778
- end
779
-
780
- def do_compression data, compress, level
781
- case compress
782
- when nil then return data
783
- when :deflate
784
- data = Zlib::Deflate.deflate(data,level)
785
- when :gzip
786
- data = IO.pipe { |r,w|
787
- gzip = Zlib::GzipWriter.new(w,level)
788
- gzip.write data
789
- gzip.close
790
- r.read
791
- }
792
- else raise ArgumentError
793
- end
794
- data
795
- end
796
-
797
- private :init_hasher, :do_compression
798
-
799
- # Specify the data for the Binary object. The src must either be an IO object
800
- # or a string containing a file path and name or an ArgumentError will be raised.
801
- # Deflate compression by default, level 9, pass in :gzip to use Gzip compression
802
- # or nil to disable compression entirely. The length and compression fields will
803
- # automatically be set. This method will NOT close the src IO when it's done, you'll
804
- # need to handle that yourself. Currently this doesn't do any error handling
805
- # on the IO read. Also, it currently reads the entire IO stream first,
806
- # buffers it into memory, then compresses before base64 encoding...
807
- def data(src, options={:compress=>:deflate, :level=>9, :hash=>:md5})
808
- compress = options.fetch :compress, :deflate
809
- level = options.fetch :level, 9
810
- hash = options.fetch :hash, :md5
811
-
812
- if src.is_a? String
813
- File.open(src, 'r') {|f| data f, options }
814
- else
815
- raise ArgumentError unless src.is_a? IO
816
-
817
- # Optionally generate a hash over the data as it is read
818
- if hash
819
- hasher = init_hasher(hash)
820
- d = src.read {|block| hasher.update block }
821
- self[hash] = hasher.hexdigest
822
- else
823
- d = src.read
824
- end
825
-
826
- # Set the uncompressed length of the data in octets
827
- self[:length] = d.length
828
-
829
- # Apply compression if necessary
830
- if compress
831
- d = do_compression d, compress, level
832
- self[:compress] = compress
833
- end
834
-
835
- # Set the data
836
- self[:data] = Base64.urlsafe_encode64(d)
837
- end
838
- end
839
-
840
- end
841
-
842
- module EventSpec
843
- include ObjectSpec
844
- def_object :attended_by, :collection, :attendedBy
845
- def_object :attending, :collection
846
- def_object :invited, :collection
847
- def_object :maybe_attending, :collection, :maybeAttending
848
- def_object :not_attended_by, :collection, :notAttendedBy
849
- def_object :not_attending, :collection, :notAttending
850
- end
851
-
852
- module IssueSpec
853
- include ObjectSpec
854
- def_string_array(:types) {|v| is_absolute_iri? v }
855
-
856
- def type m, &block
857
- property :types, m, &block
858
- end
859
- end
860
-
861
- module PermissionsSpec
862
- include ObjectSpec
863
- def_object :scope
864
- def_string_array :actions
865
-
866
- def action m, &block
867
- property :actions, m, &block
868
- end
869
- end
870
-
871
- module RGSpec # For "role" and "group" objects
872
- include ObjectSpec
873
- def_object :members, :collection
874
- end
875
-
876
- module TaskSpec
877
- include ActivitySpec
878
- def_date_time :by
879
- def_object_array :prerequisites, :task
880
- def_object_array :supersedes, :task
881
-
882
- def prerequisite m, &block
883
- property :prerequisites, m, &block
884
- end
885
-
886
- def supersede m, &block
887
- property :supersedes, m, &block
888
- end
889
-
890
- end
891
-
892
- module ImageSpec
893
- include ObjectSpec
894
- def_object :full_image, :media_link, :fullImage
895
- end
896
-
897
- module BookmarkSpec
898
- include ObjectSpec
899
- def_absolute_iri :target_url, :targetUrl
900
- end
901
-
902
- module LinkSpec
903
- include ObjectSpec
904
- def_absolute_iri :href
905
- def_string :title
906
- def_string :hreflang do |x| is_lang_tag? x end # must be a RFC 4646 tag
907
- def_string :type do |x| is_mime_type? x end # must be a valid MIME Media Type
908
- end
909
-
910
- module LinksSpec
911
- include Spec
912
- # Require that all properties on the Links spec are link objects
913
- def missing_check v
914
- v.one_of_type? Hash, LinkSpec
915
- end
916
-
917
- def link rel, include_object_type=false, &block
918
- self[rel.to_sym] = ASObj.generate :link, !include_object_type, &block
919
- end
920
-
921
- def link_with_object_type rel, &block
922
- link rel, true, &block
923
- end
924
- end
925
-
926
- # Collect the various Specs and map to their respective object types
927
- SPECS = {
928
- nil => ObjectSpec,
929
- :activity => ActivitySpec,
930
- :media_link => MediaLinkSpec,
931
- :mood => MoodSpec,
932
- :address => AddressSpec,
933
- :place => PlaceSpec,
934
- :position => PositionSpec,
935
- :collection => CollectionSpec,
936
- :audio => AVSpec,
937
- :video => AVSpec,
938
- :binary => BinarySpec,
939
- :file => FileSpec,
940
- :event => EventSpec,
941
- :issue => IssueSpec,
942
- :permission => PermissionsSpec,
943
- :role => RGSpec,
944
- :group => RGSpec,
945
- :task => TaskSpec,
946
- :product => ImageSpec,
947
- :image => ImageSpec,
948
- :link => LinkSpec,
949
- :links => LinksSpec
950
- }
951
-
952
- # override or add a new spec... be careful here.. the existing
953
- # spec definitions can be overridden
954
- def add_spec sym, spec
955
- SPECS[sym] = spec
956
- end
957
-
958
- # create a new Spec module
959
- def spec *specs, &block
960
- o = Module.new.extend Spec, Spec::Defs, *specs
961
- o.module_exec &block
962
- o
963
- end
964
-
965
- # create a new Spec module based on ObjectSpec
966
- def object_spec *specs, &block
967
- spec ObjectSpec, *specs, &block
968
- end
969
-
970
- # define the template method as an alias to lambda
971
- alias :template :lambda
972
-
973
- module_function :add_spec, :spec, :object_spec
974
-
975
- # syntactic sugar
976
- LENIENT, STRICT = true, false
977
-
978
- # basic priorities...
979
- HIGHEST, HIGH, MEDIUM, NORMAL, LOW, LOWEST, NONE = 1.0, 0.75, 0.50, 0.50, 0.25, 0.00, 0.00
980
-
981
- # Provide additional , currently experimental object types and features
982
- # These may change at any time...
983
- module Experimental
984
- extend ActivityStreams
985
-
986
- ANY = :'*'
987
-
988
- def verb_object &block
989
- ASObj.generate :verb,false,&block
990
- end
991
-
992
- # Experimental!! May change.. see http://goo.gl/x2XZl
993
- module VerbSpec
994
- include ObjectSpec
995
- verb_check = ->(x){is_verb? x}
996
- def_string :value, &verb_check
997
- def_string_array :hypernyms, &verb_check
998
- def_string_array :synonyms, &verb_check
999
- def_object_array :objects, :object_combination
1000
-
1001
- def combo &block
1002
- ASObj.generate :object_combination,true,&block
1003
- end
1004
-
1005
- def hypernym x
1006
- property :hypernyms, x
1007
- end
1008
-
1009
- def synonym x
1010
- property :synonyms, x
1011
- end
1012
-
1013
- def obj x, &block
1014
- property :foos, x, &block
1015
- end
1016
- end
1017
-
1018
- module ObjectCombinationSpec
1019
- include Spec
1020
- def_string :actor
1021
- def_string :obj, :object
1022
- def_string :target
1023
- def_boolean :target_required, :targetRequired
1024
- def_object :templates, :object_templates
1025
-
1026
- def target t, required=false, &block
1027
- property :target, t, &block
1028
- target_required if required
1029
- end
1030
-
1031
- end
1032
-
1033
- module ObjectTemplatesSpec
1034
- include Spec
1035
- def missing_checker v
1036
- v.is_a? String
1037
- end
1038
- end
1039
-
1040
- add_spec :verb, VerbSpec
1041
- add_spec :object_combination, ObjectCombinationSpec
1042
- add_spec :object_templates, ObjectTemplatesSpec
1043
-
1044
- end # END EXPERIMENTAL MODULE
1045
-
1046
- end
1047
-
1048
- # some syntactic sugar for Fixnums... useful for
1049
- # working with Time .. e.g. updated now - 1.week #updated one week ago
1050
- class Fixnum
1051
-
1052
- # true if this number is within the given range
1053
- def within? r
1054
- raise ArgumentError if not r.is_a?Range
1055
- r.include? self
1056
- end unless method_defined?(:within?)
1057
-
1058
- # treats the fixnum as a representation of a number
1059
- # of milliseconds, returns the approximate total number
1060
- # of seconds represented e.g. 1000.milliseconds => 1
1061
- # fractional seconds are truncated (rounded down)
1062
- def milliseconds
1063
- self / 1000
1064
- end unless method_defined?(:milliseconds)
1065
-
1066
- # treats the fixnum as a representation of a number
1067
- # of seconds
1068
- def seconds
1069
- self
1070
- end unless method_defined?(:seconds)
1071
-
1072
- # treats the fixnum as a representation of a
1073
- # number of minutes and returns the total number
1074
- # of seconds represented.. e.g. 2.minutes => 120,
1075
- # 3.minutes => 180
1076
- def minutes
1077
- seconds * 60
1078
- end unless method_defined?(:minutes)
1079
-
1080
- # treats the fixnum as a representation of a
1081
- # number of hours and returns the total number
1082
- # of seconds represented.. e.g. 2.hours => 7200
1083
- def hours
1084
- minutes * 60
1085
- end unless method_defined?(:hours)
1086
-
1087
- # treats the fixnum as a representation of a
1088
- # number of days and returns the total number
1089
- # of seconds represented.. e.g. 2.days => 172800
1090
- def days
1091
- hours * 24
1092
- end unless method_defined?(:days)
1093
-
1094
- # treats the fixnum as a representatin of a
1095
- # number of weeks and returns the total number
1096
- # of seconds represented.. e.g. 2.weeks => 1209600
1097
- def weeks
1098
- days * 7
1099
- end unless method_defined?(:weeks)
1100
-
1101
- alias second seconds unless method_defined?(:second)
1102
- alias minute minutes unless method_defined?(:minute)
1103
- alias hour hours unless method_defined?(:hour)
1104
- alias day days unless method_defined?(:day)
1105
- alias week weeks unless method_defined?(:week)
1106
-
1107
- end
8
+ REQUIRED_VERSION = '1.9.3'
9
+ raise "The streams gem currently requires Ruby version #{REQUIRED_VERSION} or higher" if RUBY_VERSION < REQUIRED_VERSION
10
+ require 'streams/activitystreams'