liner 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +42 -3
- data/Rakefile +1 -0
- data/lib/ext/class.rb +5 -0
- data/lib/liner.rb +25 -81
- data/lib/liner/base.rb +7 -0
- data/lib/liner/equalizable.rb +13 -0
- data/lib/liner/hashable.rb +30 -0
- data/lib/liner/inspectable.rb +9 -0
- data/lib/liner/serializable.rb +21 -0
- data/lib/liner/version.rb +3 -0
- data/liner.gemspec +1 -1
- data/test/liner/equalizable_test.rb +19 -0
- data/test/liner/hashable_test.rb +32 -0
- data/test/liner/inspectable_test.rb +9 -0
- data/test/liner_test.rb +18 -78
- data/test/test_helper.rb +15 -0
- metadata +17 -2
data/README.md
CHANGED
@@ -1,6 +1,47 @@
|
|
1
1
|
# Liner
|
2
2
|
|
3
|
-
|
3
|
+
Lay a liner for your basic Ruby classes. Basically, it's a solid foundation for a PORO (Plain Old Ruby Object). A Liner is something like a more flexible Struct or a less magical OpenStruct, with enhanced inheritability.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
You can setup a Liner based class in any of these equivalent ways:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
Engine = Liner.new(:layout, :fuel)
|
11
|
+
```
|
12
|
+
```ruby
|
13
|
+
class Engine < Liner.new(:layout, :fuel)
|
14
|
+
end
|
15
|
+
```
|
16
|
+
```ruby
|
17
|
+
class Engine
|
18
|
+
liner :layout, :fuel
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
It comes with a hash based initializer and a nice inspector.
|
23
|
+
```ruby
|
24
|
+
e = Engine.new(layout: 'V8', fuel: "gasoline") # => #<Engine layout="V8", fuel="gasoline">
|
25
|
+
```
|
26
|
+
|
27
|
+
Attribute getters and setters are built in.
|
28
|
+
```ruby
|
29
|
+
e.fuel # => "gasoline"
|
30
|
+
e.fuel = "diesel" # => "diesel"
|
31
|
+
```
|
32
|
+
|
33
|
+
Attributes are accessible via hash-style lookup too.
|
34
|
+
```ruby
|
35
|
+
e[:layout] # => "V8"
|
36
|
+
e[:layout] = "V6" # => "V6"
|
37
|
+
e[:foo] = "Bar" # => ArgumentError: Invalid liner attribute: 'foo'
|
38
|
+
```
|
39
|
+
|
40
|
+
Equality methods are also availble.
|
41
|
+
```ruby
|
42
|
+
e.eql? Engine.new(layout: 'I4') # => false
|
43
|
+
e == Engine.new(layout: 'V6', fuel: 'diesel') # => true
|
44
|
+
```
|
4
45
|
|
5
46
|
## Installation
|
6
47
|
|
@@ -16,9 +57,7 @@ Or install it yourself as:
|
|
16
57
|
|
17
58
|
$ gem install liner
|
18
59
|
|
19
|
-
## Usage
|
20
60
|
|
21
|
-
TODO: Write usage instructions here
|
22
61
|
|
23
62
|
## Contributing
|
24
63
|
|
data/Rakefile
CHANGED
data/lib/ext/class.rb
ADDED
data/lib/liner.rb
CHANGED
@@ -1,88 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def inherited(child)
|
17
|
-
child.table_keys = (child.table_keys + self.table_keys).uniq
|
18
|
-
end
|
19
|
-
|
20
|
-
def table_keys
|
21
|
-
@table_keys ||= []
|
1
|
+
require 'liner/version'
|
2
|
+
require 'liner/base'
|
3
|
+
require 'liner/hashable'
|
4
|
+
require 'liner/equalizable'
|
5
|
+
require 'liner/inspectable'
|
6
|
+
require 'liner/serializable'
|
7
|
+
require 'ext/class'
|
8
|
+
|
9
|
+
module Liner
|
10
|
+
def self.included(base)
|
11
|
+
[Base, Hashable, Equalizable, Inspectable, Serializable].each do |mod|
|
12
|
+
base.send :include, mod
|
22
13
|
end
|
23
|
-
protected :table_keys
|
24
|
-
|
25
|
-
def table_keys=(keys)
|
26
|
-
keys = keys.map(&:to_sym)
|
27
|
-
keys.each do |key|
|
28
|
-
define_method(key) do
|
29
|
-
self[key]
|
30
|
-
end
|
31
|
-
define_method("#{key}=") do |value|
|
32
|
-
self[key] = value
|
33
|
-
end
|
34
|
-
end
|
35
|
-
@table_keys = keys
|
36
|
-
end
|
37
|
-
protected :table_keys=
|
38
|
-
end
|
39
|
-
|
40
|
-
def initialize(hash=nil)
|
41
|
-
@table = table_keys.inject({}){ |h,k| h[k]=nil; h }
|
42
|
-
if hash
|
43
|
-
hash.each do |k,v|
|
44
|
-
self[k] = hash[k]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def table_keys
|
50
|
-
self.class.send(:table_keys)
|
51
14
|
end
|
52
|
-
|
15
|
+
end
|
53
16
|
|
54
|
-
|
55
|
-
|
56
|
-
|
17
|
+
def Liner.new(*keys)
|
18
|
+
apply Class.new, *keys
|
19
|
+
end
|
57
20
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
21
|
+
def Liner.apply(base, *keys)
|
22
|
+
keys = keys.map(&:to_sym).uniq
|
23
|
+
base.class_eval do
|
24
|
+
define_method(:liner_keys){ keys }
|
25
|
+
include Liner
|
26
|
+
keys.each do |key|
|
27
|
+
define_method(key){ self[key] }
|
28
|
+
define_method("#{key}="){ |value| self[key] = value }
|
64
29
|
end
|
65
30
|
end
|
66
|
-
|
67
|
-
def to_h
|
68
|
-
@table.dup
|
69
|
-
end
|
70
|
-
|
71
|
-
attr_reader :table
|
72
|
-
protected :table
|
73
|
-
|
74
|
-
def ==(other)
|
75
|
-
return false unless other.class == self.class
|
76
|
-
@table == other.table
|
77
|
-
end
|
78
|
-
|
79
|
-
def eql?(other)
|
80
|
-
return false unless other.class == self.class
|
81
|
-
@table.eql?(other.table)
|
82
|
-
end
|
83
|
-
|
84
|
-
def inspect
|
85
|
-
attribute_string = @table.map{|k,v| "#{k}=#{v.inspect}"}.join(', ')
|
86
|
-
"#<#{self.class} #{attribute_string}>"
|
87
|
-
end
|
31
|
+
base
|
88
32
|
end
|
data/lib/liner/base.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Liner
|
2
|
+
module Hashable
|
3
|
+
|
4
|
+
def liner
|
5
|
+
@liner ||= liner_keys.inject({}) { |h,k| h[k]=nil; h }
|
6
|
+
end
|
7
|
+
|
8
|
+
def liner=(hash)
|
9
|
+
hash.each { |k,v| self[k] = hash[k] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
liner[key.to_sym]
|
14
|
+
end
|
15
|
+
|
16
|
+
def []=(key,value)
|
17
|
+
key = key.to_sym
|
18
|
+
if liner_keys.include?(key)
|
19
|
+
liner[key] = value
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Invalid liner attribute: '#{key}'."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_h
|
26
|
+
liner.dup
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Liner
|
2
|
+
module Serializable
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def json_create(o)
|
9
|
+
new o['liner']
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def as_json(*)
|
14
|
+
{ 'json_class' => self.class.name, 'liner' => liner }
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_json(*args)
|
18
|
+
as_json.to_json(*args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/liner.gemspec
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
describe Liner::Equalizable do
|
2
|
+
subject { Pizza.new(crust: 'thin', sauce: 'tomato') }
|
3
|
+
describe "#==" do
|
4
|
+
it "should return true when hashes are equal" do
|
5
|
+
subject.must_be :==, Pizza.new(crust: 'thin', sauce: 'tomato')
|
6
|
+
end
|
7
|
+
it "should return false when hashes are not equal" do
|
8
|
+
subject.wont_be :==, Pizza.new(crust: 'thick', sauce: 'alfredo')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
describe "#eql?" do
|
12
|
+
it "should return true when hashes are equal" do
|
13
|
+
subject.must_be :eql?, Pizza.new(crust: 'thin', sauce: 'tomato')
|
14
|
+
end
|
15
|
+
it "should return false when hashes are not equal" do
|
16
|
+
subject.wont_be :eql?, Pizza.new(crust: 'thick', sauce: 'alfredo')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
describe Liner::Hashable do
|
2
|
+
subject { Beer.new(hops: 'Cascade') }
|
3
|
+
|
4
|
+
it "#[] should read attributes" do
|
5
|
+
subject[:hops].must_equal "Cascade"
|
6
|
+
subject[:yeast].must_equal nil
|
7
|
+
end
|
8
|
+
|
9
|
+
it "#[]= should set attributes" do
|
10
|
+
subject[:yeast]= "Top Fermenting"
|
11
|
+
subject.yeast.must_equal "Top Fermenting"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "#[]= should not set invalid attributes" do
|
15
|
+
->{ subject[:foo] = 'bar' }.must_raise ArgumentError
|
16
|
+
end
|
17
|
+
|
18
|
+
it "liner should be a hash of attributes" do
|
19
|
+
subject.liner.must_equal({ hops: 'Cascade', yeast: nil })
|
20
|
+
end
|
21
|
+
|
22
|
+
it "liner= should set the attributes" do
|
23
|
+
hash = {hops: 'Columbus', yeast: 'Bottom Fermenting' }
|
24
|
+
subject.liner = hash
|
25
|
+
subject.liner.must_equal(hash)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "#to_h should return the attribute hash" do
|
29
|
+
subject.to_h.must_equal({ hops: 'Cascade', yeast: nil })
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
describe Liner::Inspectable do
|
2
|
+
subject { Burger.new(meat: 'turkey') }
|
3
|
+
it "#inspect must include all attributes" do
|
4
|
+
subject.inspect.must_equal '#<Burger bun=nil, meat="turkey", cheese=nil>'
|
5
|
+
end
|
6
|
+
it "#to_s must include all attributes" do
|
7
|
+
subject.to_s.must_equal '#<Burger bun=nil, meat="turkey", cheese=nil>'
|
8
|
+
end
|
9
|
+
end
|
data/test/liner_test.rb
CHANGED
@@ -1,85 +1,25 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
|
3
1
|
describe Liner do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class Beer < Liner.new(:name)
|
14
|
-
end
|
15
|
-
|
16
|
-
describe Beer do
|
17
|
-
subject { Beer.new(name: "Pabst") }
|
18
|
-
it "::new must create a new instance" do
|
19
|
-
subject.must_be_instance_of Beer
|
20
|
-
subject.must_be_kind_of Liner
|
21
|
-
end
|
22
|
-
|
23
|
-
it "#[] should read attributes" do
|
24
|
-
subject[:name].must_equal "Pabst"
|
25
|
-
end
|
26
|
-
|
27
|
-
it "#[]= should set attributes" do
|
28
|
-
subject[:name]= "High Life"
|
29
|
-
subject.name.must_equal "High Life"
|
30
|
-
end
|
31
|
-
|
32
|
-
it "#[]= should not set invalid attributes" do
|
33
|
-
->{ subject[:foo] = 'bar' }.must_raise ArgumentError
|
34
|
-
end
|
35
|
-
|
36
|
-
it "#inspect must include all attributes" do
|
37
|
-
subject.inspect.must_equal '#<Beer name="Pabst">'
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "#==" do
|
41
|
-
it "should return true when hashes are equal" do
|
42
|
-
subject.must_be :==, Beer.new(name: 'Pabst')
|
2
|
+
describe :new do
|
3
|
+
let(:beer) { Beer.new(hops: 'columbus') }
|
4
|
+
let(:pizza) { Pizza.new(crust: 'thin') }
|
5
|
+
let(:burger){ Burger.new(bun: 'sesame') }
|
6
|
+
it "should create a new class" do
|
7
|
+
[Beer, Pizza, Burger].all?{|klass| klass.is_a? Class }
|
43
8
|
end
|
44
|
-
it "should
|
45
|
-
|
9
|
+
it "should define liner_keys" do
|
10
|
+
beer.liner_keys.must_equal [:hops, :yeast]
|
11
|
+
pizza.liner_keys.must_equal [:crust, :sauce]
|
12
|
+
burger.liner_keys.must_equal [:bun, :meat, :cheese]
|
46
13
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
14
|
+
it "should define attribute getters" do
|
15
|
+
beer.must_respond_to :hops
|
16
|
+
pizza.must_respond_to :sauce
|
17
|
+
burger.must_respond_to :meat
|
51
18
|
end
|
52
|
-
it "should
|
53
|
-
|
19
|
+
it "should define attribute setters" do
|
20
|
+
beer.must_respond_to :yeast=
|
21
|
+
pizza.must_respond_to :crust=
|
22
|
+
burger.must_respond_to :bun=
|
54
23
|
end
|
55
24
|
end
|
56
|
-
|
57
|
-
it "#to_h should return the table" do
|
58
|
-
subject.to_h.must_equal name: 'Pabst'
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
PaleAle = Beer.new_subclass(:hops)
|
63
|
-
describe PaleAle do
|
64
|
-
subject { PaleAle.new(name: "Sierra Nevada", hops: "Cascade") }
|
65
|
-
|
66
|
-
it "::new must create a new instance" do
|
67
|
-
subject.must_be_instance_of PaleAle
|
68
|
-
subject.must_be_kind_of Beer
|
69
|
-
subject.must_be_kind_of Liner
|
70
|
-
end
|
71
|
-
|
72
|
-
it "#name must get the name" do
|
73
|
-
subject.name.must_equal "Sierra Nevada"
|
74
|
-
end
|
75
|
-
|
76
|
-
it "#hops must get the hops" do
|
77
|
-
subject.hops.must_equal "Cascade"
|
78
|
-
end
|
79
|
-
|
80
|
-
it "#hops= must set the hops" do
|
81
|
-
subject.hops = nil
|
82
|
-
subject.hops.must_equal nil
|
83
|
-
end
|
84
|
-
|
85
25
|
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/pride'
|
3
|
+
require 'liner'
|
4
|
+
|
5
|
+
|
6
|
+
# create some dummy classes to test against with each of the supported usages.
|
7
|
+
|
8
|
+
Beer = Liner.new :hops, :yeast
|
9
|
+
|
10
|
+
class Pizza < Liner.new(:crust, :sauce)
|
11
|
+
end
|
12
|
+
|
13
|
+
class Burger
|
14
|
+
liner :bun, :meat, :cheese
|
15
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: liner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -71,9 +71,20 @@ files:
|
|
71
71
|
- LICENSE.txt
|
72
72
|
- README.md
|
73
73
|
- Rakefile
|
74
|
+
- lib/ext/class.rb
|
74
75
|
- lib/liner.rb
|
76
|
+
- lib/liner/base.rb
|
77
|
+
- lib/liner/equalizable.rb
|
78
|
+
- lib/liner/hashable.rb
|
79
|
+
- lib/liner/inspectable.rb
|
80
|
+
- lib/liner/serializable.rb
|
81
|
+
- lib/liner/version.rb
|
75
82
|
- liner.gemspec
|
83
|
+
- test/liner/equalizable_test.rb
|
84
|
+
- test/liner/hashable_test.rb
|
85
|
+
- test/liner/inspectable_test.rb
|
76
86
|
- test/liner_test.rb
|
87
|
+
- test/test_helper.rb
|
77
88
|
homepage: https://github.com/joshwlewis/liner
|
78
89
|
licenses:
|
79
90
|
- MIT
|
@@ -100,5 +111,9 @@ signing_key:
|
|
100
111
|
specification_version: 3
|
101
112
|
summary: A liner for Ruby objects. Add attribute, inspection, and equality methods.
|
102
113
|
test_files:
|
114
|
+
- test/liner/equalizable_test.rb
|
115
|
+
- test/liner/hashable_test.rb
|
116
|
+
- test/liner/inspectable_test.rb
|
103
117
|
- test/liner_test.rb
|
118
|
+
- test/test_helper.rb
|
104
119
|
has_rdoc:
|