webfinger-jrd 0.0.1

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 (3) hide show
  1. data/lib/wfjrd/wfjrd.rb +722 -0
  2. data/lib/wfjrd.rb +9 -0
  3. metadata +46 -0
@@ -0,0 +1,722 @@
1
+ ##############################################
2
+ # Author: James M Snell (jasnell@gmail.com) #
3
+ # License: Apache v2.0 #
4
+ # #
5
+ # A simple WebFinger implementation. #
6
+ # (forgive me... my ruby's a bit rusty) #
7
+ # #
8
+ # example use: #
9
+ # require 'webfinger' #
10
+ # include WebFinger #
11
+ # #
12
+ # STDOUT << jrd { #
13
+ # pretty #
14
+ # subject 'acct:me@here.com' #
15
+ # expires now + 1.day #
16
+ # aka [ #
17
+ # 'http://example.com', #
18
+ # 'http://example.net' #
19
+ # ] #
20
+ # properties { #
21
+ # property 'http://example.org', 'foo' #
22
+ # } #
23
+ # link { #
24
+ # rel 'foo' #
25
+ # href 'http://example.org' #
26
+ # type 'application/json' #
27
+ # } #
28
+ # } #
29
+ # #
30
+ # #
31
+ ##############################################
32
+ require 'json'
33
+ require "time"
34
+ require 'addressable/uri'
35
+ require 'base64'
36
+ require 'zlib'
37
+ require 'i18n'
38
+ require 'mime/types'
39
+
40
+ class Hash
41
+ # allows a Hash to be used in place of an
42
+ # ASObj ... we don't necessarily want a
43
+ # mixin on this, so just set a property
44
+ def __object_type= ot
45
+ @object_type = ot
46
+ end
47
+
48
+ def __object_type
49
+ @object_type
50
+ end
51
+
52
+ end
53
+
54
+ class Object
55
+
56
+ # Tests whether the method exists. Unlike the std method, however,
57
+ # does not throw a NameError if it doesn't. Just returns false
58
+ def method? sym
59
+ method sym rescue false
60
+ end
61
+
62
+ # Tests to see if the Object is one of several possible types
63
+ # like is_a? but accepting multiple arguments
64
+ def one_of_type? *args
65
+ args.any? {|x| is_a? x}
66
+ end
67
+
68
+ end
69
+
70
+ module WebFinger
71
+
72
+ # Provides a number of generally useful utilities methods
73
+ module Matchers
74
+ include Addressable
75
+
76
+ # true if m validates as a isegment-nz-nc as defined by RFC 3987.
77
+ def is_token? m
78
+ return false if m == nil
79
+ m = m.to_s
80
+ (m =~ /^([a-zA-Z0-9\-\.\_\~]|\%[0-9a-fA-F]{2}|[\!\$\&\'\(\)\*\+\,\;\=\@])+$/) != nil
81
+ end
82
+
83
+ # true if m is parseable as an IRI and is absolute
84
+ def is_absolute_iri? m
85
+ URI.parse(m).absolute? rescue false
86
+ end
87
+
88
+ # true if m is a valid MIME Media Type
89
+ def is_mime_type? m
90
+ MIME::Type.new m rescue false
91
+ end
92
+
93
+ # true if m is a valid RFC 4646 Lang tag
94
+ def is_lang_tag? m
95
+ I18n::Locale::Tag::Rfc4646.tag m rescue false
96
+ end
97
+
98
+ # utility method providing the basic structure of validation
99
+ # checkers for the various fields...
100
+ def checker &block
101
+ ->(v) do
102
+ raise ArgumentError unless block.call v
103
+ v
104
+ end
105
+ end
106
+
107
+ module_function :checker, :is_token?, :is_absolute_iri?, :is_mime_type?, :is_lang_tag?
108
+
109
+ end
110
+
111
+ # Defines the basic functions for the WebFinger JRD DSL
112
+ module Makers
113
+
114
+ # Create a new object by copying another.
115
+ # A list of properties to omit from the new
116
+ # copy can be provided a variable arguments.
117
+ # For instance, if you have an existing activity
118
+ # object and wish to copy everything but the
119
+ # current verb and actor properties, you could
120
+ # call new_act = copy_from(old_act, :verb, :actor) { ... }
121
+ def copy_from(other,*without,&block)
122
+ JrdObj.from other,*without,&block
123
+ end
124
+
125
+ # Create a new JRD Object
126
+ def jrd(&block)
127
+ JrdObj.generate :jrd,&block
128
+ end
129
+
130
+ def _link(&block)
131
+ JrdObj.generate :link,&block
132
+ end
133
+
134
+ # Utility method for returning the current time
135
+ def now
136
+ Time.now.utc
137
+ end
138
+
139
+ end
140
+
141
+ def checker &block
142
+ Matchers.checker &block
143
+ end
144
+
145
+ module_function :checker
146
+
147
+ include Makers, Matchers
148
+
149
+ # Represents a basic JRD Object...
150
+ # Instances, once created, are immutable for
151
+ # all the core properties. The object maintains
152
+ # an internal hash and performs basic input
153
+ # validation to ensure that the built object
154
+ # conforms to the basic requirements of the
155
+ # JRD specification. Specific
156
+ # validation requirements are defined by the
157
+ # Spec module associated with the object_type
158
+ # specified for the JrdObj instance
159
+ class JrdObj
160
+ include Makers
161
+
162
+ def initialize object_type=nil
163
+ @_ = {}
164
+ @_.__object_type = object_type
165
+ @object_type = object_type
166
+ extend SPECS[object_type] || SPECS[nil]
167
+ strict
168
+ end
169
+
170
+ # Puts this JrdObj into lenient validation mode
171
+ def lenient
172
+ @lenient = true
173
+ end
174
+
175
+ # Puts this JrdObj into strict validation mode
176
+ def strict
177
+ @lenient = false
178
+ end
179
+
180
+ # Tells this JrdObj to generate formatted JSON output
181
+ def pretty
182
+ @pretty = true
183
+ end
184
+
185
+ # true if this JrdObj has been configured to generate formatted JSON output
186
+ def pretty?
187
+ @pretty || false
188
+ end
189
+
190
+ # true if this JrdObj is operating in lenient mode
191
+ def lenient?
192
+ @lenient
193
+ end
194
+
195
+ # true if this JrdObj is operating in strict mode
196
+ def strict?
197
+ !lenient?
198
+ end
199
+
200
+ # the internal object type identifier for this JrdObj
201
+ def __object_type
202
+ @object_type
203
+ end
204
+
205
+ # return a frozen copy of the internal hash
206
+ def finish
207
+ @_.dup.freeze
208
+ end
209
+
210
+ # write this thing out, the param must repond to the << operator for appending
211
+ def append_to out
212
+ raise ArgumentError unless out.respond_to?:<<
213
+ out << to_s
214
+ end
215
+ alias :>> append_to
216
+
217
+ # force pretty printing
218
+ def pretty_to out
219
+ out << JSON.pretty_generate(@_)
220
+ end
221
+
222
+ # generates a copy of this object
223
+ def copy_of *without, &block
224
+ JrdObj.from self, *without, &block
225
+ end
226
+
227
+ def to_s
228
+ pretty? ? JSON.pretty_generate(@_) : @_.to_json
229
+ end
230
+
231
+ def [] k
232
+ @_[send("alias_for_#{k}".to_sym) || k]
233
+ end
234
+ protected :[]
235
+
236
+ # Sets a value on the internal hash without any type checking
237
+ # if v is an instance of JrdObj, finish will be called
238
+ # to get the frozen hash ...
239
+ def set k,v
240
+ key = k.to_s.to_sym
241
+ v = (v.is_a?(JrdObj) ? v.finish : v) unless v == nil
242
+ @_[key] = v unless v == nil
243
+ @_.delete key if v == nil
244
+ end
245
+ alias :[]= :set
246
+
247
+ def freeze
248
+ @_.freeze
249
+ super
250
+ end
251
+
252
+ # Within the generator, any method call that has exactly one
253
+ # parameter will be turned into a member of the underlying hash
254
+ def property m, *args, &block
255
+ # Return nil if it's looking for an unknown alias_for_* method
256
+ return nil if m =~ /^alias\_for\_.*/
257
+
258
+ # Special magic... if an unknown ? method is called, it's treated
259
+ # as a check against the internal hash to see if the given field
260
+ # has been set. For instance, priority? will check to see if the
261
+ # priority field has been set
262
+ return @_.has_key?(m.to_s[0...-1].to_sym) if m =~ /.*\?/
263
+
264
+ # Is it an unknown to_ method? e.g. to_ary ... if so, fall through to default
265
+ if m =~ /^to\_.*/
266
+ super
267
+ return
268
+ end
269
+
270
+ # Once we get past the special cases, check to see if we have the
271
+ # expected number of arguments.
272
+ if !args.length.within?(1..2)
273
+ raise NoMethodError
274
+ return
275
+ end
276
+
277
+ # Now we start to figure out the exact value to set
278
+ transform, alias_for, checker = [:transform_,:alias_for_,:check_].map {|x| "#{x}#{m}".to_sym }
279
+
280
+ v = args[0]
281
+
282
+ # First, if the value given is a JrdObj, call finish on it
283
+ v = (v.is_a?(JrdObj) ? v.finish : v) unless v == nil
284
+
285
+ # If it's an Enumerable, but not a Hash, convert to an Array using Map,
286
+ # If each of the member items are JrdObj's call finish.
287
+ v = v.map {|i| i.is_a?(JrdObj) ? i.finish : i } if v.is_a?(Enumerable) && !v.is_a?(Hash)
288
+
289
+ # If the value is a Time object, let's make sure it's ISO 8601
290
+ v = v.iso8601 if v.is_a? Time
291
+
292
+ # Finally, do the object_type specific transform, if any
293
+ # note, this could potentially undo the previous checks if
294
+ # the transform provided by a given spec module isn't well
295
+ # behaved. that's ok tho, we'll trust that it's doing the
296
+ # right thing and just move on ... we're going to be validating
297
+ # next anyway
298
+ v = send transform, v if method? transform
299
+
300
+ # Now let's do validation... unless lenient is set
301
+ if !args[1] && strict?
302
+ ok = method?(checker) ? send(checker,v) : missing_check(v)
303
+ raise ArgumentError unless ok
304
+ end
305
+ m = send alias_for if method? alias_for
306
+ @_[m] = v unless v == nil
307
+ @_.delete m if v == nil
308
+ end
309
+ alias :method_missing :property
310
+
311
+ end
312
+
313
+ class << JrdObj
314
+
315
+ # Performs the actual work of creating an JrdObj and executing
316
+ # the associated block to build it up, then freezing the
317
+ # JrdObj before returning it
318
+ def generate object_type=nil, &block
319
+ m = JrdObj.new object_type
320
+ m.instance_eval &block unless not block_given?
321
+ m.freeze
322
+ end
323
+
324
+ # Creates a new JrdObj by copying from another one
325
+ def from other, *without, &block
326
+ raise ArgumentError unless other.one_of_type?(JrdObj,Hash)
327
+ m = JrdObj.new other.__object_type
328
+ m.pretty if other.pretty?
329
+ m.lenient if other.lenient?
330
+ other.finish.each_pair {|k,y| m[k] = y unless without.include? k }
331
+ m.instance_eval &block unless not block_given?
332
+ m.freeze
333
+ end
334
+
335
+ end
336
+
337
+ # The base module for all Validation Spec Modules.. these
338
+ # define the requirements for the various WebFinger
339
+ # object types
340
+ module Spec
341
+
342
+ # by default, allow all values if a specific check hasn't been provided
343
+ # Spec modules can override this behavior by defining their own missing_check
344
+ def missing_check v
345
+ true
346
+ end
347
+
348
+ # Defines the various utility methods used to build Spec modules
349
+ module Defs
350
+
351
+ # Maps an input symbol to a property name in the hash
352
+ def def_alias sym, name
353
+ define_method("alias_for_#{sym}".to_sym) {
354
+ name
355
+ } if name
356
+ module_function "alias_for_#{sym}".to_sym
357
+ end
358
+
359
+ # Defines the method for validating the value of a
360
+ # specific property.
361
+ def def_checker sym, &block
362
+ sym = "check_#{sym}".to_sym
363
+ define_method sym,&block
364
+ module_function sym
365
+ end
366
+
367
+ # Defines a transform for the value of a specific property
368
+ def def_transform sym, &block
369
+ sym = "transform_#{sym}".to_sym
370
+ if block_given?
371
+ define_method sym,&block
372
+ else
373
+ define_method(sym) {|v|v} # just return self if no transform defined
374
+ end
375
+ module_function sym
376
+ end
377
+
378
+ # Mark def_alias, def_checker and def_transform as private
379
+ # these should only be called from within the Defs module
380
+ private :def_alias, :def_checker, :def_transform
381
+
382
+ # Define a property as being an absolute IRI
383
+ def def_absolute_iri sym, name=nil
384
+ def_transform(sym) {|v|
385
+ next nil if v == nil
386
+ Addressable::URI.parse(v)
387
+ }
388
+ def_checker(sym) { |v|
389
+ # v must be an absolute IRI
390
+ !v || is_absolute_iri?(v)
391
+ }
392
+ def_alias sym, name if name
393
+ end
394
+
395
+ # Define a property as being an ISO 8601 DateTime
396
+ def def_date_time sym, name=nil
397
+ def_transform(sym) {|v|
398
+ next v if v == nil || v.is_a?(Time)
399
+ Time.parse(v.to_s).iso8601 rescue v
400
+ }
401
+ def_checker(sym) { |v|
402
+ # v must be parseable as a time
403
+ next true if v == nil || v.is_a?(Time)
404
+ Time.parse(v.to_s) rescue next false
405
+ true
406
+ }
407
+ def_alias sym, name if name
408
+ end
409
+
410
+ # Define a property as being an IRI ... does not have to be absolute
411
+ def def_iri sym, name=nil
412
+ def_transform(sym) {|v|
413
+ next nil if v == nill
414
+ Addressable::URI.parse(v)}
415
+ def_checker(sym) { |v|
416
+ # v must be parseable as a URI
417
+ !v || Addressable::URI.parse(v) rescue false
418
+ }
419
+ def_alias sym, name if name
420
+ end
421
+
422
+ # Define a property as being a string, an additional block
423
+ # can be passed in to perform additional checking (e.g. regex matching, etc)
424
+ def def_string sym, name=nil, &block
425
+ def_transform(sym) {|v|
426
+ next nil if v == nil
427
+ v.to_s
428
+ }
429
+ def_checker(sym) { |v|
430
+ # v will be converted to a string, then checked against the optional
431
+ # block... if the block returns false, raise a validation error
432
+ next true if v == nil
433
+ next block.call(v.to_s) if block_given?
434
+ true
435
+ }
436
+ def_alias sym, name if name
437
+ end
438
+
439
+ # Define a property as being an JrdObj.
440
+ def def_object sym, object_type=nil, name=nil
441
+ def_transform(sym)
442
+ def_checker(sym) { |v|
443
+ next true if v == nil
444
+ # v must be an instance of the given object_type
445
+ if object_type
446
+ next false if v.__object_type != object_type
447
+ end
448
+ # right now this is pretty strict... we only allow Hash or JrdObj
449
+ # instances to be passed. TODO: see if we can relax this to enable
450
+ # more flexible duck typing ...
451
+ v.one_of_type? Hash, JrdObj
452
+ }
453
+ def_alias sym, name if name
454
+ def_property(sym, object_type, name) if object_type
455
+ end
456
+
457
+ # Define a property as being an Array of JrdObj's
458
+ def def_object_array sym, object_type=nil, name=nil
459
+ def_alias sym, name if name
460
+ def_transform(sym) {|v|
461
+ next nil if v == nil
462
+ orig = self[sym]
463
+ if v.is_a?(Array)
464
+ next orig ? orig + v : v
465
+ end
466
+ orig ? orig << v : [v]
467
+ }
468
+ def_checker(sym) { |v|
469
+ next true if v == nil
470
+ # v must be either an array or enumerable and each item
471
+ # must be either a Hash or JrdObj that matches the given
472
+ # object_type, if any
473
+ next false unless (v.one_of_type?(Array, Enumerable) && !v.is_a?(Hash))
474
+ v.each {|x|
475
+ return false unless x.one_of_type? JrdObj, Hash
476
+ return false if (object_type && x.__object_type != object_type)
477
+ }
478
+ true
479
+ }
480
+ end
481
+
482
+ # Define a property as being an Array of Strings, an additional
483
+ # block can be passed to perform additional checking
484
+ def def_string_array sym, name=nil, &block
485
+ def_transform(sym) {|v|
486
+ next nil if v == nil
487
+ orig = self[sym]
488
+ if v.one_of_type? Array, Enumerable
489
+ add = v.map {|x| x.to_s}
490
+ next orig ? orig + add : add
491
+ end
492
+ orig ? orig << v.to_s : [v.to_s]
493
+ }
494
+ def_checker(sym) { |v|
495
+ next true if v == nil
496
+ next false unless (v.one_of_type?(Array, Enumerable) && !v.is_a?(Hash))
497
+ v.each {|x|
498
+ return false unless block.call(x)
499
+ } if block_given?
500
+ true
501
+ }
502
+ def_alias sym, name if name
503
+ end
504
+
505
+ def def_boolean sym, name=nil
506
+ def_transform(sym) {|v|
507
+ next false if v == nil
508
+ v ? true : false
509
+ }
510
+ def_checker(sym) { |v|
511
+ v.one_of_type? TrueClass, FalseClass
512
+ }
513
+ def_alias sym, name if name
514
+
515
+ module_eval %Q/def #{sym}() property(:'#{sym}', true) end/
516
+ module_eval %Q/def not_#{sym}() property(:'#{sym}', false) end/
517
+ end
518
+
519
+ # Define a property as being a Numeric
520
+ def def_numeric sym, name=nil, &block
521
+ def_checker(sym) { |v|
522
+ next true if v == nil
523
+ return false unless v.is_a? Numeric
524
+ if block_given?
525
+ next false unless block.call v
526
+ end
527
+ true
528
+ }
529
+ def_alias sym, name if name
530
+ end
531
+
532
+ # Define a property as being a non-negative fixnum
533
+ def def_non_negative_int sym, name=nil
534
+ def_numeric(sym, name) {|v|
535
+ next false unless (v.is_a?(Fixnum) && v >= 0)
536
+ true
537
+ }
538
+ end
539
+
540
+ # Define a property as being a float with a bounded range
541
+ def def_bound_float sym, range, name=nil
542
+ def_numeric(sym, name) {|v|
543
+ next false if (range.respond_to?(:include?) && !range.include?(v))
544
+ true
545
+ }
546
+ end
547
+
548
+ def def_property sym, type=nil, name=nil
549
+ sym = sym.to_s
550
+ module_eval %Q/
551
+ def #{sym} &block
552
+ self[:#{name || sym}] = JrdObj.generate(:#{type},&block)
553
+ end
554
+ /
555
+ end
556
+ private :def_property
557
+ end
558
+
559
+ # Ensure the the Defs module is included in all spec modules...
560
+ extend Defs
561
+ def self.included(other)
562
+ other.extend Defs
563
+ end
564
+
565
+ end
566
+
567
+ # The base spec for all JrdObj's
568
+ module ObjectSpec
569
+ include Spec
570
+
571
+ def_object :properties, :properties, :properties
572
+
573
+ # ensure that all spec object include the Defs module...
574
+ include Defs
575
+ def self.included(other)
576
+ other.extend Defs
577
+ other.module_exec {
578
+ def self.included(o)
579
+ o.extend Defs
580
+ end
581
+ }
582
+ end
583
+
584
+ end
585
+
586
+ module JrdSpec
587
+ include ObjectSpec
588
+ def_absolute_iri :subject
589
+ def_date_time :expires
590
+ check = ->(x){ is_absolute_iri? x }
591
+ def_string_array :aka, :aliases, &check
592
+ def_object_array :links, :link, :links
593
+
594
+ def link &block
595
+ property :links, _link(&block)
596
+ end
597
+
598
+ end
599
+
600
+ module LinkSpec
601
+ include ObjectSpec
602
+ def_string :rel
603
+ def_iri :href
604
+ def_string :type do |x| is_mime_type? x end # must be a valid MIME Media Type
605
+ def_object :titles, :titles, :titles
606
+ end
607
+
608
+ module PropertiesSpec
609
+ include ObjectSpec
610
+ end
611
+
612
+ module TitlesSpec
613
+ include ObjectSpec
614
+ def missing_checker v
615
+ v.is_a? String
616
+ end
617
+ def lang lang, val
618
+ property lang.to_sym, val
619
+ end
620
+ def default val
621
+ lang '*', val
622
+ lang 'default', val
623
+ end
624
+ end
625
+
626
+ # Collect the various Specs and map to their respective object types
627
+ SPECS = {
628
+ nil => ObjectSpec,
629
+ :jrd => JrdSpec,
630
+ :link => LinkSpec,
631
+ :properties => PropertiesSpec,
632
+ :titles => TitlesSpec
633
+ }
634
+
635
+ # override or add a new spec... be careful here.. the existing
636
+ # spec definitions can be overridden
637
+ def add_spec sym, spec
638
+ SPECS[sym] = spec
639
+ end
640
+
641
+ # create a new Spec module
642
+ def spec *specs, &block
643
+ o = Module.new.extend Spec, Spec::Defs, *specs
644
+ o.module_exec &block
645
+ o
646
+ end
647
+
648
+ # create a new Spec module based on ObjectSpec
649
+ def object_spec *specs, &block
650
+ spec ObjectSpec, *specs, &block
651
+ end
652
+
653
+ # define the template method as an alias to lambda
654
+ alias :template :lambda
655
+
656
+ module_function :add_spec, :spec, :object_spec
657
+
658
+ # syntactic sugar
659
+ LENIENT, STRICT = true, false
660
+
661
+ end
662
+
663
+ # some syntactic sugar for Fixnums... useful for
664
+ # working with Time .. e.g. updated now - 1.week #updated one week ago
665
+ class Fixnum
666
+
667
+ # true if this number is within the given range
668
+ def within? r
669
+ raise ArgumentError if not r.is_a?Range
670
+ r.include? self
671
+ end unless method_defined?(:within?)
672
+
673
+ # treats the fixnum as a representation of a number
674
+ # of milliseconds, returns the approximate total number
675
+ # of seconds represented e.g. 1000.milliseconds => 1
676
+ # fractional seconds are truncated (rounded down)
677
+ def milliseconds
678
+ self / 1000
679
+ end unless method_defined?(:milliseconds)
680
+
681
+ # treats the fixnum as a representation of a number
682
+ # of seconds
683
+ def seconds
684
+ self
685
+ end unless method_defined?(:seconds)
686
+
687
+ # treats the fixnum as a representation of a
688
+ # number of minutes and returns the total number
689
+ # of seconds represented.. e.g. 2.minutes => 120,
690
+ # 3.minutes => 180
691
+ def minutes
692
+ seconds * 60
693
+ end unless method_defined?(:minutes)
694
+
695
+ # treats the fixnum as a representation of a
696
+ # number of hours and returns the total number
697
+ # of seconds represented.. e.g. 2.hours => 7200
698
+ def hours
699
+ minutes * 60
700
+ end unless method_defined?(:hours)
701
+
702
+ # treats the fixnum as a representation of a
703
+ # number of days and returns the total number
704
+ # of seconds represented.. e.g. 2.days => 172800
705
+ def days
706
+ hours * 24
707
+ end unless method_defined?(:days)
708
+
709
+ # treats the fixnum as a representatin of a
710
+ # number of weeks and returns the total number
711
+ # of seconds represented.. e.g. 2.weeks => 1209600
712
+ def weeks
713
+ days * 7
714
+ end unless method_defined?(:weeks)
715
+
716
+ alias second seconds unless method_defined?(:second)
717
+ alias minute minutes unless method_defined?(:minute)
718
+ alias hour hours unless method_defined?(:hour)
719
+ alias day days unless method_defined?(:day)
720
+ alias week weeks unless method_defined?(:week)
721
+
722
+ end
data/lib/wfjrd.rb ADDED
@@ -0,0 +1,9 @@
1
+ ##############################################
2
+ # Author: James M Snell (jasnell@gmail.com) #
3
+ # License: Apache v2.0 #
4
+ # #
5
+ # A simple WebFinger JRD implementation. #
6
+ ##############################################
7
+ REQUIRED_VERSION = '1.9.3'
8
+ raise "The webfinger gem currently requires Ruby version #{REQUIRED_VERSION} or higher" if RUBY_VERSION < REQUIRED_VERSION
9
+ require 'wfjrd/wfjrd'
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: webfinger-jrd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - James M Snell
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-18 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A WebFinger JRD DSL
15
+ email: jasnell@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/wfjrd.rb
21
+ - lib/wfjrd/wfjrd.rb
22
+ homepage: https://github.com/jasnell/webfinger
23
+ licenses: []
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubyforge_project:
42
+ rubygems_version: 1.8.24
43
+ signing_key:
44
+ specification_version: 3
45
+ summary: A WebFinger JRD DSL
46
+ test_files: []