dyna_struct 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +85 -0
- data/Rakefile +1 -0
- data/dyna_struct.gemspec +23 -0
- data/lib/dyna_struct.rb +13 -0
- data/lib/dyna_struct/accessor.rb +12 -0
- data/lib/dyna_struct/base.rb +14 -0
- data/lib/dyna_struct/full.rb +67 -0
- data/lib/dyna_struct/modifiable.rb +30 -0
- data/lib/dyna_struct/modifiable/accessor.rb +7 -0
- data/lib/dyna_struct/modifiable/base.rb +7 -0
- data/lib/dyna_struct/modifiable/reader.rb +7 -0
- data/lib/dyna_struct/reader.rb +11 -0
- data/lib/dyna_struct/version.rb +3 -0
- data/spec/lib/dyna_struct/accessor_spec.rb +7 -0
- data/spec/lib/dyna_struct/base_spec.rb +7 -0
- data/spec/lib/dyna_struct/full_spec.rb +229 -0
- data/spec/lib/dyna_struct/modifiable/accessor_spec.rb +8 -0
- data/spec/lib/dyna_struct/modifiable/base_spec.rb +8 -0
- data/spec/lib/dyna_struct/modifiable/reader_spec.rb +8 -0
- data/spec/lib/dyna_struct/reader_spec.rb +7 -0
- data/spec/modifiable_spec.rb +62 -0
- data/spec/shared_specs.rb +72 -0
- data/spec/spec_helper.rb +3 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 14bad87fe3602d8b8b591ed263f4a3c690e50627
|
4
|
+
data.tar.gz: 53fa67ed916cb526cde82872c72f4a4a11c9358d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cb99c5957906fad30aa128112a637b10d84dd0d7f0b345f93ca8bfb4735e6fa0251015f67bb6a307e158c154236ac63436a9914df8ed7055c86e6c7ede917acf
|
7
|
+
data.tar.gz: 105582c4c8d876a6fbe824e3252ff7f4ab796f32778d506d68c1afb1f9dde0e79965e838b7bba5250c203108453c2fa2208c91527c39e7757cae0acd061bc31d
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --format documentation
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 JC Wilcox
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# DynaStruct
|
2
|
+
|
3
|
+
DynaStruct offers a number of classes which provide different ways to dynamically assign and interact with instance variables.
|
4
|
+
This is accomplished through Ruby's metaprogramming, which allows the dynamic manipulation of data and methods for a specific object.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'dyna_struct'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install dyna_struct
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
The DynaStruct module provides four classes, offering different degrees of complexity:
|
23
|
+
|
24
|
+
* `DynaStruct::Base`
|
25
|
+
* `DynaStruct::Reader`
|
26
|
+
* `DynaStruct::Accessor`
|
27
|
+
* `DynaStruct::Full`
|
28
|
+
|
29
|
+
`DynaStruct::Base` contains only an initialize method, which takes a Hash and dynamically defines instance variables based on the values provided. So,
|
30
|
+
|
31
|
+
DynaStruct::Base.new(foo: 'bar')
|
32
|
+
|
33
|
+
will yield a new object with instance variable `@foo = 'bar'`.
|
34
|
+
|
35
|
+
`DynaStruct::Reader` offers this same functionality, with the addition of reader methods for instance variables.
|
36
|
+
|
37
|
+
x = DynaStruct::Reader.new(foo: 'bar)
|
38
|
+
x.foo #=> 'bar'
|
39
|
+
|
40
|
+
Similarly, `DynaStruct::Accessor` adds both getter and setter methods:
|
41
|
+
|
42
|
+
y = DynaStruct::Accessor.new(foo: 'bar')
|
43
|
+
x.foo = 7
|
44
|
+
x.foo #=> 7
|
45
|
+
|
46
|
+
`DynaStruct::Full` offers all of the above features, as well as most of the features offered by Ruby's OpenStruct class.
|
47
|
+
|
48
|
+
z = DynaStruct::Full.new(foo: 'bar')
|
49
|
+
z[:foo] #=> 'bar'
|
50
|
+
z['abc'] = 'def'
|
51
|
+
z.abc #=> 'def'
|
52
|
+
z.to_h #=> { foo: 'bar', abc: 'def' }
|
53
|
+
|
54
|
+
DynaStruct also offers a `DynaStruct::Modifiable` module, which adds three classes:
|
55
|
+
|
56
|
+
* `DynaStruct::Modifiable::Base`
|
57
|
+
* `DynaStruct::Modifiable::Reader`
|
58
|
+
* `DynaStruct::Modifiable::Accessor`
|
59
|
+
|
60
|
+
These classes correspond to the above classes, but add 3 methods: `.<<`, `.remove`, and `.empty?`,
|
61
|
+
which allow the user to make some modifications to the object after instantiation.
|
62
|
+
|
63
|
+
x = DynaStruct::Modifiable::Reader.new
|
64
|
+
x.empty? #=> true
|
65
|
+
x << { abc: 'def' }
|
66
|
+
x.empty? #=> false
|
67
|
+
x.abc #=> 'def'
|
68
|
+
x.remove(:abc) #=> 'def'
|
69
|
+
x.empty? #=> true
|
70
|
+
|
71
|
+
* * *
|
72
|
+
|
73
|
+
The biggest advantage these classes have over Ruby's OpenStruct is inheritance.
|
74
|
+
|
75
|
+
class Foo < DynaStruct::Reader; end
|
76
|
+
|
77
|
+
defines a class that can be initialized with an arbitrary Hash and automagically possess instance variables and reader methods corresponding to that Hash.
|
78
|
+
|
79
|
+
## Contributing
|
80
|
+
|
81
|
+
1. Fork it ( http://github.com/xDAGRONx/dyna_struct/fork )
|
82
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
83
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
84
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
85
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/dyna_struct.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dyna_struct/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dyna_struct"
|
8
|
+
spec.version = DynaStruct::VERSION
|
9
|
+
spec.authors = ["JC Wilcox"]
|
10
|
+
spec.email = ["84jwilcox@gmail.com"]
|
11
|
+
spec.summary = %q{An alternative to Ruby's Struct, DynaStruct allows dynamic assignment of instance variables.}
|
12
|
+
spec.description = %q{DynaStruct offers a number of classes which provide different ways to dynamically assign and interact with instance variables. This is accomplished through Ruby's metaprogramming, which allows the dynamic manipulation of data and methods for a specific object.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
data/lib/dyna_struct.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "dyna_struct/version"
|
2
|
+
require "dyna_struct/base"
|
3
|
+
require "dyna_struct/reader"
|
4
|
+
require "dyna_struct/accessor"
|
5
|
+
require "dyna_struct/modifiable"
|
6
|
+
require "dyna_struct/modifiable/base"
|
7
|
+
require "dyna_struct/modifiable/reader"
|
8
|
+
require "dyna_struct/modifiable/accessor"
|
9
|
+
require "dyna_struct/full"
|
10
|
+
|
11
|
+
module DynaStruct
|
12
|
+
# Your code goes here...
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module DynaStruct
|
2
|
+
class Accessor < Base
|
3
|
+
private
|
4
|
+
def add_attributes(args)
|
5
|
+
args.each do |k, v|
|
6
|
+
instance_variable_set("@#{k}", v)
|
7
|
+
define_singleton_method("#{k}") { instance_variable_get("@#{k}") }
|
8
|
+
define_singleton_method("#{k}=") { |value| instance_variable_set("@#{k}", value) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module DynaStruct
|
2
|
+
class Full
|
3
|
+
def initialize(args=nil)
|
4
|
+
args.each_pair do |k, v|
|
5
|
+
instance_variable_set("@#{k}", v)
|
6
|
+
add_attribute(k)
|
7
|
+
end if args.kind_of?(Hash)
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](name)
|
11
|
+
instance_variable_get("@#{name}")
|
12
|
+
end
|
13
|
+
|
14
|
+
def []=(name, value)
|
15
|
+
instance_variable_set("@#{name}", value)
|
16
|
+
add_attribute(name)
|
17
|
+
value
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_h
|
21
|
+
instance_variables.inject({}) do |result, var|
|
22
|
+
result.merge var.to_s[1..-1].to_sym => instance_variable_get(var)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
alias_method :to_hash, :to_h
|
26
|
+
|
27
|
+
def delete_field(name)
|
28
|
+
if respond_to?(name)
|
29
|
+
remove_singleton_method(name, "#{name}=")
|
30
|
+
remove_instance_variable("@#{name}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(method_id, *args)
|
35
|
+
method_name = method_id.id2name
|
36
|
+
len = args.length
|
37
|
+
if method_name.chomp!(?=)
|
38
|
+
if len != 1
|
39
|
+
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
|
40
|
+
end
|
41
|
+
self[method_name] = args.first
|
42
|
+
elsif method_name.chomp!(??)
|
43
|
+
unless len.zero?
|
44
|
+
raise ArgumentError, "wrong number of arguments (#{len} for 0)", caller(1)
|
45
|
+
end
|
46
|
+
!!self[method_name]
|
47
|
+
elsif len == 0
|
48
|
+
self[method_name]
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def add_attribute(name)
|
56
|
+
unless respond_to?(name)
|
57
|
+
define_singleton_method("#{name}") { instance_variable_get("@#{name}") }
|
58
|
+
define_singleton_method("#{name}=") { |value| instance_variable_set("@#{name}", value) }
|
59
|
+
end
|
60
|
+
name
|
61
|
+
end
|
62
|
+
|
63
|
+
def remove_singleton_method(*method_names)
|
64
|
+
singleton_class.send(:remove_method, *method_names)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module DynaStruct
|
2
|
+
module Modifiable
|
3
|
+
def <<(args)
|
4
|
+
add_attributes args if args.kind_of?(Hash)
|
5
|
+
self
|
6
|
+
end
|
7
|
+
|
8
|
+
def remove(*vars)
|
9
|
+
result = vars.map do |var|
|
10
|
+
remove_singleton_method(var.to_s) if singleton_method_defined?(var.to_s)
|
11
|
+
remove_singleton_method("#{var}=") if singleton_method_defined?("#{var}=")
|
12
|
+
remove_instance_variable("@#{var}") if instance_variable_defined?("@#{var}")
|
13
|
+
end
|
14
|
+
result.length == 1 ? result.first : result
|
15
|
+
end
|
16
|
+
|
17
|
+
def empty?
|
18
|
+
instance_variables.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def remove_singleton_method(method_name)
|
23
|
+
singleton_class.send(:remove_method, method_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def singleton_method_defined?(method_name)
|
27
|
+
singleton_class.send(:method_defined?, method_name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DynaStruct::Full do
|
4
|
+
describe '.new' do
|
5
|
+
subject { described_class.new(info) }
|
6
|
+
|
7
|
+
context 'given a hash' do
|
8
|
+
context 'with valid info' do
|
9
|
+
let(:info) { { a: ?a, b: ?b, ab: 12, a18: nil } }
|
10
|
+
|
11
|
+
it 'should assign instance variables corresponding to the Hash' do
|
12
|
+
info.each do |key, value|
|
13
|
+
subject.instance_variable_get("@#{key}")
|
14
|
+
.should eq value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should create getter and setter methods' do
|
19
|
+
info.each do |key, value|
|
20
|
+
should respond_to(key)
|
21
|
+
subject.send(key).should eq value
|
22
|
+
should respond_to("#{key}=")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with invalid keys' do
|
28
|
+
let(:info) { { 9 => 2, ?@ => 4 } }
|
29
|
+
|
30
|
+
it 'should raise an exception' do
|
31
|
+
expect { subject }.to raise_exception(NameError)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'given anything besides a hash' do
|
37
|
+
it 'should return an empty DynaStruct' do
|
38
|
+
[:hi, 0, -1, 5, '', ?a, 'abc', nil, false, true, 1.05, [1,?b,3.0]].each do |arg|
|
39
|
+
test = described_class.new(arg)
|
40
|
+
test.should be_a(described_class)
|
41
|
+
test.instance_variables.should be_empty
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '.[]' do
|
48
|
+
let(:info) { { a: ?a, b: ?b } }
|
49
|
+
|
50
|
+
context 'given a valid attribute' do
|
51
|
+
subject { described_class.new(info)[:a] }
|
52
|
+
|
53
|
+
it 'should return the associated value' do
|
54
|
+
should eq ?a
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'given an invalid attribute' do
|
59
|
+
subject { described_class.new(info)[:c] }
|
60
|
+
|
61
|
+
it 'should return nil' do
|
62
|
+
should be_nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'given an impossible attribute' do
|
67
|
+
subject { described_class.new(info)['@99'] }
|
68
|
+
|
69
|
+
it { expect { subject }.to raise_exception(NameError) }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '.[]=' do
|
74
|
+
subject { described_class.new(b: 3) }
|
75
|
+
|
76
|
+
it 'should return the value' do
|
77
|
+
subject.[]=(:c, 12).should eq 12
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'setting a new attribute' do
|
81
|
+
before { subject[:a] = 2 }
|
82
|
+
|
83
|
+
it 'should set the instance variable' do
|
84
|
+
subject.instance_variable_get(:@a).should eq 2
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should create getter and setter methods' do
|
88
|
+
should respond_to(:a)
|
89
|
+
subject.a.should eq 2
|
90
|
+
should respond_to(:a=)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'attribute already exists' do
|
95
|
+
before { subject[:b] = 5 }
|
96
|
+
|
97
|
+
it 'should override the value' do
|
98
|
+
subject.instance_variable_get(:@b).should eq 5
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should not break getters or setters' do
|
102
|
+
should respond_to(:b)
|
103
|
+
subject.b.should eq 5
|
104
|
+
should respond_to(:b=)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'setting an impossible attribute' do
|
109
|
+
subject { described_class.new['@99'] = 12 }
|
110
|
+
|
111
|
+
it { expect { subject }.to raise_exception(NameError) }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '.to_h' do
|
116
|
+
subject { described_class.new(info) }
|
117
|
+
let(:info) { { a: ?a, b: ?b, ab: 12, a18: nil } }
|
118
|
+
|
119
|
+
it 'should return the hash of instance variables and values' do
|
120
|
+
subject.to_h.should eq info
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should use symbols as keys' do
|
124
|
+
subject.to_h.keys.each do |key|
|
125
|
+
key.should be_a(Symbol)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should return the variable names without the @' do
|
130
|
+
subject.to_h.keys.each do |key|
|
131
|
+
key.to_s[0].should_not eq(?@)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '.delete_field' do
|
137
|
+
subject { described_class.new(info) }
|
138
|
+
let(:info) { { a: ?a, b: ?b, ab: 12, a18: nil } }
|
139
|
+
|
140
|
+
context 'field exists' do
|
141
|
+
it 'should remove the getter and setter methods' do
|
142
|
+
subject.delete_field(:a)
|
143
|
+
should_not respond_to :a
|
144
|
+
should_not respond_to :a=
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should remove the instance variable' do
|
148
|
+
subject.delete_field(:a)
|
149
|
+
subject.instance_variable_get(:@a).should be_nil
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'should return the value of the deleted variable' do
|
153
|
+
subject.delete_field(:a).should eq info[:a]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context 'field does not exist' do
|
158
|
+
it 'should not raise error' do
|
159
|
+
expect { subject.delete_field(:charlie) }.not_to raise_exception
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should return nil' do
|
163
|
+
subject.delete_field(:charlie).should be_nil
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '.method_missing' do
|
169
|
+
subject { described_class.new(info) }
|
170
|
+
let(:info) { { a: ?a, b: ?b, ab: 12, a18: nil } }
|
171
|
+
|
172
|
+
context 'given method ending in =' do
|
173
|
+
context 'given more than 1 argument' do
|
174
|
+
it 'should raise an argument error' do
|
175
|
+
expect { subject.send('beta=', 19, 3) }.to raise_exception(ArgumentError)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'given no arguments' do
|
180
|
+
it 'should raise an argument error' do
|
181
|
+
expect { subject.send('beta=') }.to raise_exception(ArgumentError)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'given a single argument' do
|
186
|
+
it 'should set the instance variable' do
|
187
|
+
subject.beta = 19
|
188
|
+
subject.instance_variable_get(:@beta).should eq 19
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'should create getter and setter methods' do
|
192
|
+
subject.beta = 19
|
193
|
+
should respond_to(:beta)
|
194
|
+
subject.beta.should eq 19
|
195
|
+
should respond_to(:beta=)
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should return the value' do
|
199
|
+
subject.send('beta=', 19).should eq 19
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'given a method ending in ?' do
|
205
|
+
context 'given an argument' do
|
206
|
+
it { expect { subject.beta?(12) }.to raise_exception(ArgumentError) }
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'not given an argument' do
|
210
|
+
it 'should return the boolean value of the attribute' do
|
211
|
+
subject.beta?.should be_false
|
212
|
+
subject.a?.should be_true
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context 'given a method not ending in = or ?' do
|
218
|
+
context 'given no arguments' do
|
219
|
+
it 'should return nil' do
|
220
|
+
subject.hello.should be_nil
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context 'given an argument' do
|
225
|
+
it { expect { subject.alpha(2) }.to raise_exception(NoMethodError) }
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
shared_examples 'Modifiable' do
|
2
|
+
describe '.<<' do
|
3
|
+
subject { new_struct << info }
|
4
|
+
let(:info) { { hi: 'hello' } }
|
5
|
+
let(:new_struct) { described_class.new }
|
6
|
+
|
7
|
+
it 'should return self' do
|
8
|
+
should be_a(described_class)
|
9
|
+
should be(new_struct)
|
10
|
+
end
|
11
|
+
|
12
|
+
def adding_method(args)
|
13
|
+
described_class.new << args
|
14
|
+
end
|
15
|
+
|
16
|
+
include_examples 'add_attributes'
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '.empty?' do
|
20
|
+
subject { described_class.new }
|
21
|
+
|
22
|
+
it { should respond_to(:empty?) }
|
23
|
+
|
24
|
+
context 'no attributes assigned' do
|
25
|
+
it { should be_empty }
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'attributes assigned' do
|
29
|
+
before(:each) { subject << { hi: 'hello' } }
|
30
|
+
|
31
|
+
it { should_not be_empty }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.remove' do
|
36
|
+
subject { described_class.new info }
|
37
|
+
let(:info) { { a: ?a, b: ?b } }
|
38
|
+
|
39
|
+
context 'passed valid attributes' do
|
40
|
+
it 'should return the array of deleted values' do
|
41
|
+
subject.remove(*info.keys).should eq info.values
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should return just the value if one attribute given' do
|
45
|
+
subject.remove(info.keys.first).should eq info.values.first
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'passed invalid attributes' do
|
50
|
+
it 'should return nil for those attributes' do
|
51
|
+
subject.remove(:a, 'boop').should eq [?a, nil]
|
52
|
+
subject.remove('boop').should be_nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'passed nothing' do
|
57
|
+
it 'should return an empty array' do
|
58
|
+
subject.remove.should eq []
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
shared_examples 'DynaStruct.new' do
|
2
|
+
def adding_method(args)
|
3
|
+
described_class.new args
|
4
|
+
end
|
5
|
+
|
6
|
+
include_examples 'add_attributes'
|
7
|
+
end
|
8
|
+
|
9
|
+
shared_examples 'DynaStruct::Reader.new' do
|
10
|
+
include_examples 'DynaStruct.new'
|
11
|
+
|
12
|
+
subject { described_class.new info }
|
13
|
+
let(:info) { { a: ?a, b: ?b, ab: 12, a18: nil } }
|
14
|
+
|
15
|
+
it 'should create getter methods' do
|
16
|
+
info.each do |key, value|
|
17
|
+
should respond_to(key)
|
18
|
+
subject.send(key).should eq value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
shared_examples 'DynaStruct::Accessor.new' do
|
24
|
+
include_examples 'DynaStruct::Reader.new'
|
25
|
+
|
26
|
+
subject { described_class.new info}
|
27
|
+
let(:info) { { a: ?a, b: ?b, ab: 12, a18: nil } }
|
28
|
+
|
29
|
+
it 'should create setter methods' do
|
30
|
+
info.each do |key, value|
|
31
|
+
should respond_to("#{key}=")
|
32
|
+
expect { subject.send("#{key}=", -2) }
|
33
|
+
.not_to raise_exception
|
34
|
+
subject.send(key).should eq -2
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
shared_examples 'add_attributes' do
|
40
|
+
context 'given a Hash' do
|
41
|
+
subject { adding_method(info) }
|
42
|
+
|
43
|
+
context 'with valid info' do
|
44
|
+
let(:info) { { a: ?a, b: ?b, ab: 12, a18: nil } }
|
45
|
+
|
46
|
+
it 'should assign instance variables corresponding to the Hash' do
|
47
|
+
info.each do |key, value|
|
48
|
+
subject.instance_variable_get("@#{key}")
|
49
|
+
.should eq value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with invalid keys' do
|
55
|
+
let(:info) { { 9 => 2, ?@ => 4 } }
|
56
|
+
|
57
|
+
it 'should raise an exception' do
|
58
|
+
expect { subject }.to raise_exception(NameError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'given anything that is not a Hash' do
|
64
|
+
it 'should not change the DynaStruct' do
|
65
|
+
[:hi, 0, -1, 5, '', ?a, 'abc', nil, false, true, 1.05, [1,?b,3.0]].each do |arg|
|
66
|
+
subject = adding_method(arg)
|
67
|
+
subject.should be_a(described_class)
|
68
|
+
subject.instance_variables.should eq []
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dyna_struct
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- JC Wilcox
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: DynaStruct offers a number of classes which provide different ways to
|
42
|
+
dynamically assign and interact with instance variables. This is accomplished through
|
43
|
+
Ruby's metaprogramming, which allows the dynamic manipulation of data and methods
|
44
|
+
for a specific object.
|
45
|
+
email:
|
46
|
+
- 84jwilcox@gmail.com
|
47
|
+
executables: []
|
48
|
+
extensions: []
|
49
|
+
extra_rdoc_files: []
|
50
|
+
files:
|
51
|
+
- .gitignore
|
52
|
+
- .rspec
|
53
|
+
- Gemfile
|
54
|
+
- LICENSE.txt
|
55
|
+
- README.md
|
56
|
+
- Rakefile
|
57
|
+
- dyna_struct.gemspec
|
58
|
+
- lib/dyna_struct.rb
|
59
|
+
- lib/dyna_struct/accessor.rb
|
60
|
+
- lib/dyna_struct/base.rb
|
61
|
+
- lib/dyna_struct/full.rb
|
62
|
+
- lib/dyna_struct/modifiable.rb
|
63
|
+
- lib/dyna_struct/modifiable/accessor.rb
|
64
|
+
- lib/dyna_struct/modifiable/base.rb
|
65
|
+
- lib/dyna_struct/modifiable/reader.rb
|
66
|
+
- lib/dyna_struct/reader.rb
|
67
|
+
- lib/dyna_struct/version.rb
|
68
|
+
- spec/lib/dyna_struct/accessor_spec.rb
|
69
|
+
- spec/lib/dyna_struct/base_spec.rb
|
70
|
+
- spec/lib/dyna_struct/full_spec.rb
|
71
|
+
- spec/lib/dyna_struct/modifiable/accessor_spec.rb
|
72
|
+
- spec/lib/dyna_struct/modifiable/base_spec.rb
|
73
|
+
- spec/lib/dyna_struct/modifiable/reader_spec.rb
|
74
|
+
- spec/lib/dyna_struct/reader_spec.rb
|
75
|
+
- spec/modifiable_spec.rb
|
76
|
+
- spec/shared_specs.rb
|
77
|
+
- spec/spec_helper.rb
|
78
|
+
homepage: ''
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 2.1.11
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: An alternative to Ruby's Struct, DynaStruct allows dynamic assignment of
|
102
|
+
instance variables.
|
103
|
+
test_files:
|
104
|
+
- spec/lib/dyna_struct/accessor_spec.rb
|
105
|
+
- spec/lib/dyna_struct/base_spec.rb
|
106
|
+
- spec/lib/dyna_struct/full_spec.rb
|
107
|
+
- spec/lib/dyna_struct/modifiable/accessor_spec.rb
|
108
|
+
- spec/lib/dyna_struct/modifiable/base_spec.rb
|
109
|
+
- spec/lib/dyna_struct/modifiable/reader_spec.rb
|
110
|
+
- spec/lib/dyna_struct/reader_spec.rb
|
111
|
+
- spec/modifiable_spec.rb
|
112
|
+
- spec/shared_specs.rb
|
113
|
+
- spec/spec_helper.rb
|