squares 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +189 -0
- data/Rakefile +7 -0
- data/lib/squares/base.rb +144 -0
- data/lib/squares/version.rb +3 -0
- data/lib/squares.rb +6 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/squares/base_spec.rb +164 -0
- data/spec/squares_spec.rb +7 -0
- data/squares.gemspec +26 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 09592e711ca540e1b0fb97bb9e841af69cb34175
|
4
|
+
data.tar.gz: e3d626d74d1184b164f5ba4f90b1cf1c7567610e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 60351a2a9e968f992a4c578e2853729a090d15e3c4ec0d9d8d153d99686eb7b81081c4808ad3485d35ed71938ea3130b0079ec9f3d2bfc6ac888881128d4e3df
|
7
|
+
data.tar.gz: fc865c89c8de7e4fbbb5f6ffc0ca5e344a772848b29456f2cbc7618ede6c6e601e2c38951a2b088fad7aed3e166b76262510d1808961fe5cfe6788ae019e6ee0
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Joel Helbling
|
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,189 @@
|
|
1
|
+
# Squares \[\*\]
|
2
|
+
|
3
|
+
A lightweight ORM backed by any hash-like storage. Hand-crafted from a solid piece of pure
|
4
|
+
aircraft-grade Ruby and drawing distilled awesomeness from atmospheric pollutants, its only
|
5
|
+
dependency is you.
|
6
|
+
|
7
|
+
## Installation Blah, Blah, Blah
|
8
|
+
|
9
|
+
_I swear, this part of the README just rolled right out of `bundle gem squares`._
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'squares'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install squares
|
24
|
+
|
25
|
+
_And yeah, I did enjoy typing `bundle gem squares`. It sounds like something to
|
26
|
+
eat. Now I'm hungry._
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
_Because you are going to use it._
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
require 'squares'
|
34
|
+
```
|
35
|
+
|
36
|
+
### Write Models
|
37
|
+
|
38
|
+
_How come they never write back?_
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
class Person < Squares::Base
|
42
|
+
properties :real_name, :age
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
You can also provide a default value if you switch to the `property` variant:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
class Person < Squares::Base
|
50
|
+
property :eye_color, default: 'brown'
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
### Bootstrapping
|
55
|
+
|
56
|
+
_A funny word for "setup & configure". Bootstrapping. Bootstrapping. See? Funny._
|
57
|
+
|
58
|
+
Now you can bootstrap `;)` your model to a hash-like storage object like so:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
people_storage = Redis::Namespace.new(
|
62
|
+
Person.underscore_name,
|
63
|
+
:redis => $redis_connection )
|
64
|
+
|
65
|
+
Person.store = people_storage
|
66
|
+
```
|
67
|
+
|
68
|
+
Or setup a bunch of 'em like this:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
[Person, Place, Thing].each do |model|
|
72
|
+
model.store = LevelDB::DB.new("./tmp/#{model.underscore_name}")
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
...or if you just want to use a plain ole in-memory hash:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
tom_sellecks_mustache = {}
|
80
|
+
Soup.store = tom_sellecks_mustache
|
81
|
+
```
|
82
|
+
|
83
|
+
Squares actually defaults the store to an empty hash, which means if you're ok
|
84
|
+
with in-memory, transient storage (e.g. when writing tests, etc.) you don't have
|
85
|
+
to do any config-- er, bootstrapping `;)` at all!
|
86
|
+
|
87
|
+
### Onward To The Fun
|
88
|
+
|
89
|
+
Squares does not auto-generate an `:id` for each new object --you'll do that
|
90
|
+
and it will be used as the "key" in the hash storage. In the following example,
|
91
|
+
we're creating a new `Person` and using 'spiderman' as the key:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
pete = Person.new('spiderman', real_name: 'Peter Parker', age: 17)
|
95
|
+
# ^^^ key ^^^ ^^^^^^^^^^^ properties ^^^^^^^^^^^
|
96
|
+
pete.save
|
97
|
+
|
98
|
+
Person.has_key? 'spiderman' #=> true
|
99
|
+
pete.id #=> 'spiderman'
|
100
|
+
```
|
101
|
+
|
102
|
+
When we retrieve an object, it returns an instance of that model:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
wallcrawler = Person['spiderman']
|
106
|
+
wallcrawler = Person.find 'spiderman' #=> same, shmame.
|
107
|
+
wallcrawler.id #=> 'spiderman'
|
108
|
+
wallcrawler.real_name #=> 'Peter Parker'
|
109
|
+
wallcrawler.class #=> Person
|
110
|
+
```
|
111
|
+
|
112
|
+
Of course, for some types of storage, the model object has to be serialized and
|
113
|
+
de-serialized when it's stored and retrieved. Squares uses `Marshal.dump` and
|
114
|
+
`Marshal.restore` to do that. This means that custom marshalling can be added
|
115
|
+
to your models (see [documentation on ruby Marshal][marshal]).
|
116
|
+
|
117
|
+
### Even More Fun
|
118
|
+
|
119
|
+
You can use the ActiveRecord-esque `.where` method with a block to retrieve records
|
120
|
+
for which the block returns true:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
Person.where { |p| p.left_handed == true } #=> all the lefties
|
124
|
+
```
|
125
|
+
|
126
|
+
The `.where` method is actually just an alias of `.select`...which means, yeah!
|
127
|
+
Squares are enumerable, yay!
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
Person.map(&:name) #=> an array containing all the names
|
131
|
+
```
|
132
|
+
|
133
|
+
### What It Doesn't Do
|
134
|
+
|
135
|
+
Much like Wolverine, Squares doesn't do relationships. You'll have to
|
136
|
+
maintain those in your code. If you have an issue with that, leave me
|
137
|
+
an issue, and I'll think about what that might mean.
|
138
|
+
|
139
|
+
Squares neither knows nor cares about the type or contents of your model
|
140
|
+
instance's properties. This has consequences.
|
141
|
+
|
142
|
+
First, anything you stash had darn well better be marshal-able, or there
|
143
|
+
will be blood on the roller-rink. Or at least errors. Yeah, I've made
|
144
|
+
sure there won't be blood (you're welcome), but watch out for errors.
|
145
|
+
If you run into problems, refer to the [documentation on ruby Marshal][marshal].
|
146
|
+
|
147
|
+
Second, there is no magic-fu for stuff like generating question methods
|
148
|
+
for boolean properties. For example, it doesn't make a `#left_handed?` method
|
149
|
+
out of your `property :left_handed`). But hey, you know what you can
|
150
|
+
do? Behold:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
class Person
|
154
|
+
property :awesome?, default: true #=> What?! is that a "?"
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
Ok, don't interrupt me, I'm selling here...
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
you = Person.new
|
162
|
+
you.awesome? #=> true
|
163
|
+
```
|
164
|
+
|
165
|
+
Of course, Squares doesn't mind how you use `#awesome?` and the corresponding `#awesome=` methods:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
you.awesome = 'yak hair'
|
169
|
+
you.awesome? #=> 'yak hair'
|
170
|
+
```
|
171
|
+
|
172
|
+
or
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
you.awesome = nil
|
176
|
+
you.awesome? #=> nil
|
177
|
+
```
|
178
|
+
|
179
|
+
But hey, who cares, as long as yak hair is truthy?
|
180
|
+
|
181
|
+
[marshal]:http://www.ruby-doc.org/core-2.1.5/Marshal.html
|
182
|
+
|
183
|
+
## Contributing
|
184
|
+
|
185
|
+
1. Fork it ( https://github.com/joelhelbling/squares/fork )
|
186
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
187
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
188
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
189
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/squares/base.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
module Squares
|
2
|
+
class Base
|
3
|
+
attr_accessor :id
|
4
|
+
|
5
|
+
def initialize *args
|
6
|
+
apply *args
|
7
|
+
end
|
8
|
+
|
9
|
+
def save
|
10
|
+
store[@id] = Marshal.dump self
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def == other
|
15
|
+
@id == other.id && properties_equal(other)
|
16
|
+
end
|
17
|
+
|
18
|
+
def properties
|
19
|
+
self.class.properties
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def properties_equal other
|
25
|
+
! properties.detect do |property|
|
26
|
+
self.send(property) != other.send(property)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def apply *args
|
31
|
+
@id, value_hash = *args
|
32
|
+
self.class.properties.each do |property|
|
33
|
+
value = args.last.to_h[property] || self.class.defaults[property]
|
34
|
+
# self.class.method_for(property)
|
35
|
+
self.send "#{property.to_s.gsub(/\?$/,'')}=".to_sym, value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def store
|
40
|
+
self.class.store
|
41
|
+
end
|
42
|
+
|
43
|
+
#############
|
44
|
+
class << self
|
45
|
+
include Enumerable
|
46
|
+
|
47
|
+
def [] id
|
48
|
+
if item = store[id]
|
49
|
+
Marshal.restore item
|
50
|
+
end
|
51
|
+
end
|
52
|
+
alias_method :find, :[]
|
53
|
+
|
54
|
+
def []= *args
|
55
|
+
id, instance = *args
|
56
|
+
if instance.class == self
|
57
|
+
instance.id = id
|
58
|
+
instance.save
|
59
|
+
elsif instance.respond_to?(:to_h)
|
60
|
+
self.new(id, instance).save
|
61
|
+
else
|
62
|
+
raise ArgumentError.new(<<-ERR)
|
63
|
+
You must provide an instance of #{self.name} or at least
|
64
|
+
something which responds to #to_h"
|
65
|
+
ERR
|
66
|
+
end
|
67
|
+
end
|
68
|
+
alias_method :create, :[]=
|
69
|
+
|
70
|
+
def has_key? key
|
71
|
+
store.has_key? key
|
72
|
+
end
|
73
|
+
alias_method :key?, :has_key?
|
74
|
+
alias_method :member?, :has_key?
|
75
|
+
alias_method :includes?, :has_key?
|
76
|
+
|
77
|
+
def each &block
|
78
|
+
store.values.map{ |i| Marshal.restore i }.each &block
|
79
|
+
end
|
80
|
+
alias_method :where, :select
|
81
|
+
|
82
|
+
def property prop, opts
|
83
|
+
@_properties ||= []
|
84
|
+
@_properties << prop
|
85
|
+
uniquify_properties
|
86
|
+
if prop.to_s.match(/\?$/)
|
87
|
+
define_method prop do
|
88
|
+
instance_variable_get "@#{self.class.instance_var_for prop}"
|
89
|
+
end
|
90
|
+
define_method prop.to_s.gsub(/\?$/, '=') do |v|
|
91
|
+
instance_variable_set "@#{self.class.instance_var_for prop}", v
|
92
|
+
end
|
93
|
+
else
|
94
|
+
attr_accessor prop
|
95
|
+
end
|
96
|
+
if default = opts[:default]
|
97
|
+
defaults[prop] = default
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def properties *props
|
102
|
+
props.each do |prop|
|
103
|
+
property prop, {}
|
104
|
+
end
|
105
|
+
@_properties
|
106
|
+
end
|
107
|
+
|
108
|
+
def defaults
|
109
|
+
@_defaults ||= {}
|
110
|
+
end
|
111
|
+
|
112
|
+
def underscore_name
|
113
|
+
self.name.
|
114
|
+
gsub(/::/, '/').
|
115
|
+
gsub(/([^\/])([A-Z])/, '\1_\2').
|
116
|
+
downcase
|
117
|
+
end
|
118
|
+
|
119
|
+
def store= storage
|
120
|
+
@store = storage
|
121
|
+
end
|
122
|
+
|
123
|
+
def store
|
124
|
+
@store ||= {}
|
125
|
+
end
|
126
|
+
|
127
|
+
def instance_var_for property
|
128
|
+
if property.to_s.match(/\?$/)
|
129
|
+
"#{property.to_s.gsub(/\?$/,'')}__question__".to_sym
|
130
|
+
else
|
131
|
+
property
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def uniquify_properties
|
138
|
+
@_properties = @_properties.uniq.compact
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
data/lib/squares.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'squares/base'
|
3
|
+
|
4
|
+
module Marvel
|
5
|
+
class SuperHero < Squares::Base
|
6
|
+
properties :real_name, :special_powers
|
7
|
+
end
|
8
|
+
class Villain < Squares::Base
|
9
|
+
properties :vehicle, :lair
|
10
|
+
property :really_evil?, default: true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Squares
|
15
|
+
describe Base do
|
16
|
+
Given(:storage) { {} }
|
17
|
+
Given(:test_class) { Marvel::SuperHero }
|
18
|
+
Given { test_class.store = storage }
|
19
|
+
|
20
|
+
Given(:id) { 'Captain America' }
|
21
|
+
Given(:name) { 'Steve Rogers' }
|
22
|
+
Given(:powers) { ['super strength', 'strategy', 'leadership'] }
|
23
|
+
When(:hero) { test_class.new id, real_name: name, special_powers: powers }
|
24
|
+
|
25
|
+
describe 'class' do
|
26
|
+
|
27
|
+
describe '.underscore_name' do
|
28
|
+
Then { test_class.underscore_name == 'marvel/super_hero' }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.properties' do
|
32
|
+
Then { test_class.properties == [:real_name, :special_powers] }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.use_storage' do
|
36
|
+
Given(:storage) { {attack: :fwoosh } }
|
37
|
+
When { test_class.store = storage }
|
38
|
+
Then { test_class.store == storage }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '.[]' do
|
42
|
+
Given { storage[id] = Marshal.dump hero }
|
43
|
+
When(:recovered_hero) { Marvel::SuperHero['Captain America'] }
|
44
|
+
Then { recovered_hero.class == Marvel::SuperHero }
|
45
|
+
Then { recovered_hero.id == 'Captain America' }
|
46
|
+
Then { recovered_hero.real_name == 'Steve Rogers' }
|
47
|
+
Then { recovered_hero.special_powers.include? 'leadership' }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '.[]= creates & stores a new instance' do
|
51
|
+
Given(:id) { 'Spiderman' }
|
52
|
+
Given(:name) { 'Peter Parker' }
|
53
|
+
Given(:powers) { [ 'wall crawling', 'web spinning', 'cracking wise' ] }
|
54
|
+
|
55
|
+
context 'whether created with an instance' do
|
56
|
+
Given(:instance) { test_class.new(id, real_name: name, special_powers: powers) }
|
57
|
+
|
58
|
+
When { test_class[id] = instance }
|
59
|
+
When(:spidey) { Marshal.restore storage.values.first }
|
60
|
+
|
61
|
+
Then { spidey.class == Marvel::SuperHero }
|
62
|
+
Then { spidey.id == 'Spiderman' }
|
63
|
+
Then { spidey.real_name == 'Peter Parker' }
|
64
|
+
Then { spidey.special_powers.include? 'cracking wise' }
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'or creating using a hash' do
|
68
|
+
When { test_class[id] = { real_name: name, special_powers: powers } }
|
69
|
+
|
70
|
+
When(:spidey) { Marshal.restore storage.values.first }
|
71
|
+
Then { spidey.class == Marvel::SuperHero }
|
72
|
+
Then { spidey.id == 'Spiderman' }
|
73
|
+
Then { spidey.real_name == 'Peter Parker' }
|
74
|
+
Then { spidey.special_powers.include? 'cracking wise' }
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'but creating with an invalid object' do
|
78
|
+
Then { expect{ test_class[id] = 12 } .to raise_error(ArgumentError) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '.has_key?' do
|
83
|
+
Given { hero.save }
|
84
|
+
Then { expect(test_class).to have_key(id) }
|
85
|
+
Then { expect(test_class).to be_key(id) }
|
86
|
+
Then { expect(test_class).to be_member(id) }
|
87
|
+
Then { expect(test_class).to be_includes(id) }
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'more cool stuff' do
|
91
|
+
Given do
|
92
|
+
Marvel::SuperHero['Superman'] = { real_name: 'Clark Kent', special_powers: ['flying'] }
|
93
|
+
Marvel::SuperHero['Hulk'] = { real_name: 'Bruce Banner', special_powers: ['smash'] }
|
94
|
+
Marvel::SuperHero['Batman'] = { real_name: 'Bruce Wayne', special_powers: ['stuff'] }
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '.where' do
|
98
|
+
When(:result) { Marvel::SuperHero.where { |h| h.real_name =~ /^Bruce/ } }
|
99
|
+
Then { result.count == 2 }
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'models are enumerable!' do
|
103
|
+
When(:result) { Marvel::SuperHero.map(&:special_powers).flatten }
|
104
|
+
Then { result == %w[ flying smash stuff ] }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
describe 'instances' do
|
111
|
+
describe '#{{property}}' do
|
112
|
+
Then { hero.id == id }
|
113
|
+
Then { hero.real_name == name }
|
114
|
+
Then { hero.special_powers == powers }
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#save' do
|
118
|
+
When { hero.save }
|
119
|
+
When(:frozen_hero) { Marshal.restore storage.values.first }
|
120
|
+
Then { storage.keys.first == 'Captain America' }
|
121
|
+
Then { frozen_hero.real_name == 'Steve Rogers' }
|
122
|
+
Then { frozen_hero.class == Marvel::SuperHero }
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#==' do
|
126
|
+
Given(:hero1) { test_class.new id, real_name: name, special_powers: powers }
|
127
|
+
Given(:hero2) { test_class.new id, real_name: name, special_powers: powers }
|
128
|
+
|
129
|
+
context 'when they are equal' do
|
130
|
+
Then { hero1 == hero2 }
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when some property(ies) are not equal' do
|
134
|
+
Given { hero2.real_name = 'Steven Rogers' }
|
135
|
+
Then { hero1 != hero2 }
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'default values' do
|
140
|
+
Given do
|
141
|
+
class Marvel::SuperHero < Squares::Base
|
142
|
+
property :hair_color, default: 'black'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
When(:hero) { test_class.new id, real_name: name }
|
146
|
+
Then { hero.special_powers == nil }
|
147
|
+
Then { hero.hair_color == 'black' }
|
148
|
+
Then { Marvel::SuperHero.defaults == { hair_color: 'black' } }
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "models' properties don't bleed into each other" do
|
154
|
+
When(:villain) { Marvel::Villain.new 'Dr. Octopus', vehicle: 'jets', lair: 'abandonned sewer' }
|
155
|
+
Then { villain.class == Marvel::Villain }
|
156
|
+
Then { Marvel::Villain.properties == [:vehicle, :lair, :really_evil?] }
|
157
|
+
Then { villain.properties == [:vehicle, :lair, :really_evil?] }
|
158
|
+
Then { expect(villain).to_not respond_to(:hair_color) }
|
159
|
+
Then { expect(villain).to respond_to(:really_evil?) }
|
160
|
+
Then { expect(villain).to respond_to(:really_evil=) }
|
161
|
+
Then { expect(villain).to be_really_evil }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
data/squares.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'squares/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "squares"
|
8
|
+
spec.version = Squares::VERSION
|
9
|
+
spec.authors = ["Joel Helbling"]
|
10
|
+
spec.email = ["joel@joelhelbling.com"]
|
11
|
+
spec.summary = %q{Lightweight ORM backed by any hash-like storage. [*]}
|
12
|
+
spec.description = %q{Redis, LevelDB or plain old hashes --any form of hash-like storage can be used to back Squares.}
|
13
|
+
spec.homepage = "http://github.com/joelhelbling/squares"
|
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.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "rspec-given"
|
25
|
+
spec.add_development_dependency "pry"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: squares
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joel Helbling
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-21 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.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-given
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Redis, LevelDB or plain old hashes --any form of hash-like storage can
|
84
|
+
be used to back Squares.
|
85
|
+
email:
|
86
|
+
- joel@joelhelbling.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".travis.yml"
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- lib/squares.rb
|
99
|
+
- lib/squares/base.rb
|
100
|
+
- lib/squares/version.rb
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
- spec/squares/base_spec.rb
|
103
|
+
- spec/squares_spec.rb
|
104
|
+
- squares.gemspec
|
105
|
+
homepage: http://github.com/joelhelbling/squares
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.4.3
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: Lightweight ORM backed by any hash-like storage. [*]
|
129
|
+
test_files:
|
130
|
+
- spec/spec_helper.rb
|
131
|
+
- spec/squares/base_spec.rb
|
132
|
+
- spec/squares_spec.rb
|