safestruct 0.2.0 → 1.0.0

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: 74b37cac746195871cc30eec8b8b54622958c6a5
4
- data.tar.gz: 80def63037cd23ce8812529a4f208e1ebfbbab7a
3
+ metadata.gz: c7bf46e7fc7abcced2da4628ab2640f4f3136482
4
+ data.tar.gz: 693e1ad041258390403893df801673955e574c7e
5
5
  SHA512:
6
- metadata.gz: 508027ee5576e342154bc62d6d5b5e25cf2f829a075a7b942fc9a3af2bb2295f6e6d71eec58597b7de5c69106ecde9ee6fb1f8d0c503215ab7f15735afa01f62
7
- data.tar.gz: a9172d32b881902e273bc54cb4e41875edb0c2dd40efd62ca19a07170e8cf01596457b31fa1c63fe244096c3a69b2ab9a280c93241656abedf99f1fd5eeb4c60
6
+ metadata.gz: 2f548ea0b261a9fe0e829ad2205aa21b46ea6cac99ff082a80bcaaa5418fe75e9684200f31033f099450c3b688240664949ad0bbc70ad4f8abf57f197a33020a
7
+ data.tar.gz: 9fc0faf2c9373cfa146a7f7d5d8b18e17c7ea6e419d10b19d9ab95323650d825bbb3e6b7818c475360aa89101c9f17543731bc07dd02f2e17ce102a5ede5e92e
data/LICENSE.md ADDED
@@ -0,0 +1,116 @@
1
+ CC0 1.0 Universal
2
+
3
+ Statement of Purpose
4
+
5
+ The laws of most jurisdictions throughout the world automatically confer
6
+ exclusive Copyright and Related Rights (defined below) upon the creator and
7
+ subsequent owner(s) (each and all, an "owner") of an original work of
8
+ authorship and/or a database (each, a "Work").
9
+
10
+ Certain owners wish to permanently relinquish those rights to a Work for the
11
+ purpose of contributing to a commons of creative, cultural and scientific
12
+ works ("Commons") that the public can reliably and without fear of later
13
+ claims of infringement build upon, modify, incorporate in other works, reuse
14
+ and redistribute as freely as possible in any form whatsoever and for any
15
+ purposes, including without limitation commercial purposes. These owners may
16
+ contribute to the Commons to promote the ideal of a free culture and the
17
+ further production of creative, cultural and scientific works, or to gain
18
+ reputation or greater distribution for their Work in part through the use and
19
+ efforts of others.
20
+
21
+ For these and/or other purposes and motivations, and without any expectation
22
+ of additional consideration or compensation, the person associating CC0 with a
23
+ Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24
+ and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25
+ and publicly distribute the Work under its terms, with knowledge of his or her
26
+ Copyright and Related Rights in the Work and the meaning and intended legal
27
+ effect of CC0 on those rights.
28
+
29
+ 1. Copyright and Related Rights. A Work made available under CC0 may be
30
+ protected by copyright and related or neighboring rights ("Copyright and
31
+ Related Rights"). Copyright and Related Rights include, but are not limited
32
+ to, the following:
33
+
34
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
35
+ and translate a Work;
36
+
37
+ ii. moral rights retained by the original author(s) and/or performer(s);
38
+
39
+ iii. publicity and privacy rights pertaining to a person's image or likeness
40
+ depicted in a Work;
41
+
42
+ iv. rights protecting against unfair competition in regards to a Work,
43
+ subject to the limitations in paragraph 4(a), below;
44
+
45
+ v. rights protecting the extraction, dissemination, use and reuse of data in
46
+ a Work;
47
+
48
+ vi. database rights (such as those arising under Directive 96/9/EC of the
49
+ European Parliament and of the Council of 11 March 1996 on the legal
50
+ protection of databases, and under any national implementation thereof,
51
+ including any amended or successor version of such directive); and
52
+
53
+ vii. other similar, equivalent or corresponding rights throughout the world
54
+ based on applicable law or treaty, and any national implementations thereof.
55
+
56
+ 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57
+ applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58
+ unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59
+ and Related Rights and associated claims and causes of action, whether now
60
+ known or unknown (including existing as well as future claims and causes of
61
+ action), in the Work (i) in all territories worldwide, (ii) for the maximum
62
+ duration provided by applicable law or treaty (including future time
63
+ extensions), (iii) in any current or future medium and for any number of
64
+ copies, and (iv) for any purpose whatsoever, including without limitation
65
+ commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66
+ the Waiver for the benefit of each member of the public at large and to the
67
+ detriment of Affirmer's heirs and successors, fully intending that such Waiver
68
+ shall not be subject to revocation, rescission, cancellation, termination, or
69
+ any other legal or equitable action to disrupt the quiet enjoyment of the Work
70
+ by the public as contemplated by Affirmer's express Statement of Purpose.
71
+
72
+ 3. Public License Fallback. Should any part of the Waiver for any reason be
73
+ judged legally invalid or ineffective under applicable law, then the Waiver
74
+ shall be preserved to the maximum extent permitted taking into account
75
+ Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76
+ is so judged Affirmer hereby grants to each affected person a royalty-free,
77
+ non transferable, non sublicensable, non exclusive, irrevocable and
78
+ unconditional license to exercise Affirmer's Copyright and Related Rights in
79
+ the Work (i) in all territories worldwide, (ii) for the maximum duration
80
+ provided by applicable law or treaty (including future time extensions), (iii)
81
+ in any current or future medium and for any number of copies, and (iv) for any
82
+ purpose whatsoever, including without limitation commercial, advertising or
83
+ promotional purposes (the "License"). The License shall be deemed effective as
84
+ of the date CC0 was applied by Affirmer to the Work. Should any part of the
85
+ License for any reason be judged legally invalid or ineffective under
86
+ applicable law, such partial invalidity or ineffectiveness shall not
87
+ invalidate the remainder of the License, and in such case Affirmer hereby
88
+ affirms that he or she will not (i) exercise any of his or her remaining
89
+ Copyright and Related Rights in the Work or (ii) assert any associated claims
90
+ and causes of action with respect to the Work, in either case contrary to
91
+ Affirmer's express Statement of Purpose.
92
+
93
+ 4. Limitations and Disclaimers.
94
+
95
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
96
+ surrendered, licensed or otherwise affected by this document.
97
+
98
+ b. Affirmer offers the Work as-is and makes no representations or warranties
99
+ of any kind concerning the Work, express, implied, statutory or otherwise,
100
+ including without limitation warranties of title, merchantability, fitness
101
+ for a particular purpose, non infringement, or the absence of latent or
102
+ other defects, accuracy, or the present or absence of errors, whether or not
103
+ discoverable, all to the greatest extent permissible under applicable law.
104
+
105
+ c. Affirmer disclaims responsibility for clearing rights of other persons
106
+ that may apply to the Work or any use thereof, including without limitation
107
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
108
+ disclaims responsibility for obtaining any necessary consents, permissions
109
+ or other rights required for any use of the Work.
110
+
111
+ d. Affirmer understands and acknowledges that Creative Commons is not a
112
+ party to this document and has no duty or obligation with respect to this
113
+ CC0 or use of the Work.
114
+
115
+ For more information, please see
116
+ <http://creativecommons.org/publicdomain/zero/1.0/
data/Manifest.txt CHANGED
@@ -1,4 +1,5 @@
1
1
  CHANGELOG.md
2
+ LICENSE.md
2
3
  Manifest.txt
3
4
  README.md
4
5
  Rakefile
data/README.md CHANGED
@@ -83,7 +83,7 @@ voter2 == Voter.zero #=> false
83
83
 
84
84
  Voter.zero.frozen? #=> true
85
85
 
86
- voter3 = Voter.new( 0 ) #=> ArgumentError - wrong number of arguments
86
+ voter3 = Voter.new( 0 ) #=> ArgumentError: wrong number of arguments
87
87
  # for Voter.new - 1 for 4
88
88
  ```
89
89
 
@@ -101,7 +101,7 @@ Example:
101
101
  ArrayInteger = SafeArray.build_class( Integer )
102
102
  ary = ArrayInteger.new
103
103
  ary.size #=> 0
104
- ary[0] #=> IndexError
104
+ ary[0] #=> IndexError: index 0 outside of array bounds
105
105
  ary.size = 2 #=> [0,0]
106
106
  ary[0] #=> 0
107
107
  ```
@@ -111,7 +111,7 @@ or use the `Array.of` convenience shortcut:
111
111
  ``` ruby
112
112
  ary = Array.of( Integer )
113
113
  ary.size #=> 0
114
- ary[0] #=> IndexError
114
+ ary[0] #=> IndexError: index 0 outside of array bounds
115
115
  ary.size = 2 #=> [0, 0]
116
116
  ary[0] #=> 0
117
117
 
@@ -119,7 +119,7 @@ ary[0] #=> 0
119
119
 
120
120
  another_ary = Array.of( Bool )
121
121
  another_ary.size #=> 0
122
- another_ary[0] #=> IndexError
122
+ another_ary[0] #=> IndexError: index 0 outside of array bounds
123
123
  another_ary.size = 2 #=> [false, false]
124
124
  another_ary[0] #=> false
125
125
 
@@ -135,7 +135,7 @@ Yes, Safe Array works with structs (or nested arrays or hash mappings) too. Exam
135
135
  ``` ruby
136
136
  ary = Array.of( Vote )
137
137
 
138
- ary[0] #=> IndexError
138
+ ary[0] #=> IndexError: index 0 outside of array bounds
139
139
  ary.size = 2 #=> [#<Vote @weight=0, @voted=false, @vote=0, @delegate='0x0000'>,
140
140
  # #<Vote @weight=0, @voted=false, @vote=0, @delegate='0x0000'>]
141
141
  ary[0] #=> #<Vote @weight=0, @voted=false, @vote=0, @delegate='0x0000'>
data/lib/safestruct.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'pp'
4
+ require 'forwardable' # uses def_delegator
4
5
 
5
6
 
6
7
  ## our own code
@@ -13,16 +14,24 @@ require 'safestruct/safe_struct'
13
14
 
14
15
 
15
16
  ####################################
16
- ## add dummy bool class for mapping and (payable) method signature
17
+ ## add zero/zero_new machinery for builin classes
17
18
 
19
+ #### value semantics
18
20
  class Integer
19
- def self.zero() 0; end
21
+ def self.zero() 0; end ## note: 0.frozen? == true by default
20
22
  end
21
23
 
22
24
  class Bool
23
- def self.zero() false; end
25
+ def self.zero() false; end ## note: false.frozen? == true by default
24
26
  end
25
27
 
28
+ #### reference semantics (new copy ALWAYS needed)
29
+ class String
30
+ def self.new_zero() new; end
31
+ def self.zero() @zero ||= new_zero.freeze; end
32
+ end
33
+
34
+
26
35
 
27
36
 
28
37
  #####
@@ -50,13 +59,16 @@ end
50
59
 
51
60
  class Array
52
61
  ## "typed" safe array "constructor"
53
- ## e.g. Array.of( Address ) or Array.of( Money ) or Array.of( Proposal, size: 2 ) etc.
54
- def self.of( klass_value )
62
+ ## e.g. Array.of( Address ) or Array.of( Money ) or
63
+ ## Array.of( Proposal, 2 ) etc.
64
+ def self.of( klass_value, size=0 )
55
65
  klass = Safe::SafeArray.build_class( klass_value )
56
- klass.new ## todo: add klass.new( **kwargs ) for size: 2 etc.
66
+ klass.new( size )
57
67
  end
58
68
  end
59
69
 
70
+
71
+
60
72
  module Safe
61
73
  ############################
62
74
  # note: HACK redefine built in struct in module Safe "context"
@@ -13,50 +13,84 @@ class SafeArray
13
13
  ## note: keep a class cache
14
14
  cache = @@cache ||= {}
15
15
  klass = cache[ klass_value ]
16
- return klass if klass
17
16
 
18
- klass = Class.new( SafeArray )
19
- klass.class_eval( <<RUBY )
20
- def self.klass_value
21
- @klass_value ||= #{klass_value}
22
- end
17
+ if klass.nil?
18
+
19
+ klass = Class.new( SafeArray )
20
+ klass.class_eval( <<RUBY )
21
+ def self.klass_value
22
+ @klass_value ||= #{klass_value}
23
+ end
23
24
  RUBY
24
- ## add to cache for later (re)use
25
- cache[ klass_value ] = klass
25
+ ## add to cache for later (re)use
26
+ cache[ klass_value ] = klass
27
+ end
26
28
  klass
27
29
  end
28
30
 
29
31
 
30
32
  def self.new_zero() new; end
31
- def self.zero() @zero ||= new_zero; end
33
+ def self.zero() @zero ||= new_zero.freeze; end
32
34
 
33
35
 
34
36
 
35
- def initialize
37
+ def initialize( size=0 )
36
38
  ## todo/check: if array works if value is a (nested/multi-dimensional) array
37
39
  @ary = []
40
+ self.size = size if size > 0 ## auto-init with zeros
41
+ self # return reference to self
42
+ end
43
+
44
+ def freeze
45
+ super
46
+ @ary.freeze ## note: pass on freeze to "wrapped" array
47
+ self # return reference to self
48
+ end
49
+
50
+
51
+ def ==( other )
52
+ if other.is_a?( self.class ) ## note: must be same array class
53
+ @ary == other.instance_variable_get( '@ary' ) ## compare "wrapped" array
54
+ else
55
+ false
56
+ end
38
57
  end
58
+ alias_method :eql?, :==
59
+
60
+
61
+ def size=(value)
62
+ ## todo/check: value must be greater 0 and greater than current size
63
+ diff = value - @ary.size
64
+
65
+ ## todo/check:
66
+ ## always return (deep) frozen zero object - why? why not?
67
+ ## let user change the returned zero object - why? why not?
68
+ if self.class.klass_value.respond_to?( :new_zero )
69
+ ## note: use a new unfrozen copy of the zero object
70
+ ## changes to the object MUST be possible (new "empty" modifable object expected)
71
+ diff.times { @ary << self.class.klass_value.new_zero }
72
+ else # assume value semantics e.g. Integer, Bool, etc. zero values gets replaced
73
+ ## puts "use value semantics"
74
+ diff.times { @ary << self.class.klass_value.zero }
75
+ end
76
+ self # return reference to self
77
+ end
78
+ alias_method :'length=', :'size='
79
+
39
80
 
40
81
  def []=(index, value)
82
+ ## note: use fetch
83
+ # throws / raises an IndexError exception
84
+ # if the referenced index lies outside of the array bounds
85
+ # todo/fix: is there a better way to check for index out-of-bounds error?
86
+ old_value = @ary.fetch( index )
41
87
  @ary[index] = value
42
88
  end
43
89
 
44
90
  def [](index)
45
- item = @ary[ index ]
46
- if item.nil?
47
- ## todo/check:
48
- ## always return (deep) frozen zero object - why? why not?
49
- ## let user change the returned zero object - why? why not?
50
- if self.class.klass_value.respond_to?( :new_zero )
51
- ## note: use a new unfrozen copy of the zero object
52
- ## changes to the object MUST be possible (new "empty" modifable object expected)
53
- item = self.class.klass_value.new_zero
54
- else # assume value semantics e.g. Integer, Bool, etc. zero values gets replaced
55
- ## puts "use value semantics"
56
- item = self.class.klass_value.zero
57
- end
58
- end
59
- item
91
+ ## note: throws / raises an IndexError exception
92
+ # if the referenced index lies outside of the array bounds
93
+ @ary.fetch( index )
60
94
  end
61
95
 
62
96
  def push( item )
@@ -66,7 +100,10 @@ RUBY
66
100
  @ary.push( item )
67
101
  end
68
102
 
69
- def size() @ary.size; end
70
- def length() size; end
103
+ extend Forwardable
104
+ def_delegators :@ary, :size, :length,
105
+ :each, :each_with_index
106
+
107
+
71
108
  end # class SafeArray
72
109
  end # module Safe
@@ -19,32 +19,51 @@ class SafeHash
19
19
  ## note: keep a class cache
20
20
  cache = @@cache ||= {}
21
21
  klass = cache[ klass_value ]
22
- return klass if klass
23
-
24
- klass = Class.new( SafeHash )
25
- klass.class_eval( <<RUBY )
26
- def self.klass_key
27
- @klass_key ||= #{klass_key}
28
- end
29
- def self.klass_value
30
- @klass_value ||= #{klass_value}
31
- end
22
+
23
+ if klass.nil?
24
+ klass = Class.new( SafeHash )
25
+ klass.class_eval( <<RUBY )
26
+ def self.klass_key
27
+ @klass_key ||= #{klass_key}
28
+ end
29
+ def self.klass_value
30
+ @klass_value ||= #{klass_value}
31
+ end
32
32
  RUBY
33
- ## add to cache for later (re)use
34
- cache[ klass_value ] = klass
33
+ ## add to cache for later (re)use
34
+ cache[ klass_value ] = klass
35
+ end
36
+
35
37
  klass
36
38
  end
37
39
 
38
40
 
39
41
  def self.new_zero() new; end
40
- def self.zero() @zero ||= new_zero; end
42
+ def self.zero() @zero ||= new_zero.freeze; end
41
43
 
42
44
 
43
45
  def initialize
44
46
  ## todo/check: if hash works if value is a (nested) hash
45
- @h = {}
47
+ @h = {}
46
48
  end
47
49
 
50
+ def freeze
51
+ super
52
+ @h.freeze ## note: pass on freeze to "wrapped" hash
53
+ self # return reference to self
54
+ end
55
+
56
+ def ==( other )
57
+ if other.is_a?( self.class ) ## note: must be same hash class
58
+ @h == other.instance_variable_get( '@h' ) ## compare "wrapped" hash
59
+ else
60
+ false
61
+ end
62
+ end
63
+ alias_method :eql?, :==
64
+
65
+
66
+
48
67
 
49
68
  def []=(key, value)
50
69
  @h[key] = value
@@ -73,7 +92,9 @@ RUBY
73
92
  item
74
93
  end
75
94
 
76
- def size() @h.size; end
77
- def length() size; end
95
+ extend Forwardable
96
+ def_delegators :@h, :size, :length, ## todo/fix: remove size and length for (safe) hash - why? why not?
97
+ :has_key?, :key?
98
+
78
99
  end # class SafeHash
79
100
  end # module Safe
@@ -27,11 +27,23 @@ def self.build_class( **attributes )
27
27
  end
28
28
  end
29
29
 
30
+ alias_method :old_freeze, :freeze # note: store "old" orginal version of freeze
31
+ define_method( :freeze ) do
32
+ old_freeze ## same as calling super
33
+ attributes.keys.each do |key|
34
+ instance_variable_get( "@#{key}" ).freeze
35
+ end
36
+ self # return reference to self
37
+ end
38
+
30
39
  define_method( :== ) do |other|
31
- return false unless other.is_a?( klass )
32
- attributes.keys.all? do |key|
33
- __send__( key ) == other.__send__( key )
34
- end
40
+ if other.is_a?( klass )
41
+ attributes.keys.all? do |key|
42
+ __send__( key ) == other.__send__( key )
43
+ end
44
+ else
45
+ false
46
+ end
35
47
  end
36
48
  alias_method :eql?, :==
37
49
  end
@@ -54,10 +66,14 @@ def self.build_class( **attributes )
54
66
  ## use new_zero to create a new instance!!!
55
67
  ## do NOT use the passed in reference!!!!
56
68
  values = attributes.values.map do |value|
57
- if value.is_a?(SafeStruct) ||
58
- value.is_a?(SafeArray) ||
59
- value.is_a?(SafeHash)
60
- value.class.new_zero
69
+ ## note: was: use more "generic" check for respond_to?( :new_zero )
70
+ ## value.is_a?(SafeStruct) ||
71
+ ## value.is_a?(SafeArray) ||
72
+ ## value.is_a?(SafeHash)
73
+ if value.is_a?(String) && value == '0x0000'
74
+ value.dup ## special case for Address(0) or Address.zero encoded as string for now!!!!
75
+ elsif value.class.respond_to?( :new_zero )
76
+ value.class.new_zero
61
77
  else
62
78
  ## assume "value" object / semantics (e.g. 0, false, '0x0000' etc.) and pass through
63
79
  value
@@ -3,8 +3,8 @@
3
3
 
4
4
  module Safe
5
5
 
6
- MAJOR = 0
7
- MINOR = 2
6
+ MAJOR = 1
7
+ MINOR = 0
8
8
  PATCH = 0
9
9
  VERSION = [MAJOR,MINOR,PATCH].join('.')
10
10
 
data/test/test_array.rb CHANGED
@@ -17,7 +17,7 @@ class TestArray < MiniTest::Test
17
17
 
18
18
  def test_integer
19
19
  pp Array_Integer
20
- pp ary = Array_Integer.new
20
+ pp ary = Array_Integer.new(2)
21
21
 
22
22
  assert_equal Integer, Array_Integer.klass_value
23
23
  assert_equal 0, ary[0]
@@ -28,6 +28,23 @@ def test_integer
28
28
  assert_equal 101, ary[0]
29
29
  assert_equal 102, ary[1]
30
30
 
31
+ assert_equal 2, ary.size
32
+ assert_equal 2, ary.length
33
+ assert_equal false, ary.frozen?
34
+
35
+ ary.each { |item| pp item }
36
+ ary.each_with_index { |item,i| puts "[#{i}] #{item}"}
37
+
38
+ ary.size = 3
39
+ assert_equal 3, ary.size
40
+ assert_equal 0, ary[2]
41
+ assert Array_Integer.zero != ary
42
+
43
+ pp Array_Integer.zero
44
+ assert_equal true, Array_Integer.zero.frozen?
45
+ assert_equal Array_Integer.zero, Array_Integer.zero
46
+ assert_equal Array_Integer.zero, Array_Integer.new
47
+
31
48
  ## check Array.of (uses cached classes)
32
49
  assert_equal Array_Integer, Array.of( Integer ).class
33
50
  end
@@ -35,7 +52,7 @@ end
35
52
 
36
53
  def test_bool
37
54
  pp Array_Bool
38
- pp ary = Array_Bool.new
55
+ pp ary = Array_Bool.new(2)
39
56
 
40
57
  assert_equal Bool, Array_Bool.klass_value
41
58
  assert_equal false, ary[0]
data/test/test_hash.rb CHANGED
@@ -23,6 +23,22 @@ def test_integer
23
23
  pp Hash_X_Integer
24
24
  pp h = Hash_X_Integer.new
25
25
 
26
+ assert_equal false, h.key?( '0x1111' )
27
+ assert_equal false, h.has_key?( '0x1111' )
28
+
29
+ ## todo/fix: remove size and length for (safe) hash - why? why not?
30
+ assert_equal 0, h.size
31
+ assert_equal 0, h.length
32
+
33
+ assert_equal Hash_X_Integer.zero, h
34
+ assert_equal Hash_X_Integer.zero, Hash_X_Integer.new
35
+
36
+ pp Hash_X_Integer.zero
37
+ assert_equal true, Hash_X_Integer.zero.frozen?
38
+ assert_equal false, Hash_X_Integer.new.frozen?
39
+ assert_equal false, h.frozen?
40
+
41
+
26
42
  assert_equal Integer, Hash_X_Integer.klass_value
27
43
  assert_equal 0, h['0x1111']
28
44
  assert_equal 0, h['0x2222']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safestruct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-15 00:00:00.000000000 Z
11
+ date: 2019-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -45,10 +45,12 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files:
47
47
  - CHANGELOG.md
48
+ - LICENSE.md
48
49
  - Manifest.txt
49
50
  - README.md
50
51
  files:
51
52
  - CHANGELOG.md
53
+ - LICENSE.md
52
54
  - Manifest.txt
53
55
  - README.md
54
56
  - Rakefile