liner 0.1.2 → 0.2.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -0
- data/README.md +118 -3
- data/lib/ext/class.rb +1 -1
- data/lib/liner.rb +30 -13
- data/lib/liner/base.rb +24 -2
- data/lib/liner/hashable.rb +14 -15
- data/lib/liner/version.rb +1 -1
- data/liner.gemspec +3 -2
- data/test/liner/hashable_test.rb +4 -0
- data/test/test_helper.rb +3 -1
- metadata +22 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53f068a96a64299ca295a0c1821a5232a4ec2618
|
4
|
+
data.tar.gz: 459fd2b8e24e184a5437744fa1ae3701c384d609
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98f7de6a0c3580a6dd7c8774aa7b427b7819c30a28ad1dce9fdfd362fd3c6a9742df59f2c9a0b64508e943a802a3fa422c3f442c6529827d7acf5dab9e943bd1
|
7
|
+
data.tar.gz: 7d8e902c6662b26f751bee45f120855c21e3a300a66532fe536d4be439f5063745a352691f97788cd0461086a88bba3b6ff269327354d75c0761b381cf29abf3
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,27 +1,40 @@
|
|
1
1
|
# Liner
|
2
|
+
[](https://travis-ci.org/joshwlewis/liner)
|
3
|
+
[](https://coveralls.io/r/joshwlewis/liner?branch=master)
|
4
|
+
[](http://badge.fury.io/rb/liner)
|
5
|
+
[](https://gemnasium.com/joshwlewis/liner)
|
6
|
+
[](https://codeclimate.com/github/joshwlewis/liner)
|
2
7
|
|
3
|
-
Lay a liner for your Ruby classes. Liner is designed to
|
4
|
-
with some
|
8
|
+
Lay a liner for your Ruby classes. Liner is a lightweight library designed to
|
9
|
+
enhance simple classes with some conveniences and idioms while staying out of
|
10
|
+
your way.
|
5
11
|
|
6
12
|
## Usage
|
7
13
|
|
14
|
+
### Setup
|
15
|
+
|
8
16
|
You can setup a Liner based class in any of these equivalent ways:
|
9
17
|
|
10
18
|
```ruby
|
11
19
|
Engine = Liner.new(:layout, :fuel)
|
12
20
|
```
|
21
|
+
|
13
22
|
```ruby
|
14
23
|
class Engine < Liner.new(:layout, :fuel)
|
15
24
|
end
|
16
25
|
```
|
26
|
+
|
17
27
|
```ruby
|
18
28
|
class Engine
|
19
29
|
liner :layout, :fuel
|
20
30
|
end
|
21
31
|
```
|
22
32
|
|
33
|
+
### Initialization
|
34
|
+
|
23
35
|
Your new class comes with an initializer that takes values in the order you
|
24
36
|
defined them.
|
37
|
+
|
25
38
|
```ruby
|
26
39
|
e = Engine.new('V6', 'gasoline')
|
27
40
|
# => #<Engine layout="V6", fuel="gasoline">
|
@@ -32,6 +45,8 @@ e = Engine.new(layout: 'V8', fuel: "gasoline")
|
|
32
45
|
# => #<Engine layout="V8", fuel="gasoline">
|
33
46
|
```
|
34
47
|
|
48
|
+
### Attributes
|
49
|
+
|
35
50
|
Attribute getters and setters are built in.
|
36
51
|
```ruby
|
37
52
|
e.fuel # => "gasoline"
|
@@ -39,18 +54,118 @@ e.fuel = "diesel" # => "diesel"
|
|
39
54
|
```
|
40
55
|
|
41
56
|
Attributes are accessible via hash style lookup too.
|
57
|
+
|
42
58
|
```ruby
|
43
59
|
e[:layout] # => "V8"
|
44
60
|
e[:layout] = "V6" # => "V6"
|
45
61
|
e[:foo] = "Bar" # => ArgumentError: Invalid liner attribute: 'foo'
|
46
62
|
```
|
47
63
|
|
48
|
-
|
64
|
+
If you want a full attribute hash, we have that (`to_h` and `to_hash` also work).
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
e.liner # => { :layout => 'V6', :fuel => 'diesel' }
|
68
|
+
```
|
69
|
+
|
70
|
+
### Inspection
|
71
|
+
|
72
|
+
It's always nice not to have to set up inspection (note that `to_s` is the same
|
73
|
+
here).
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
e.inspect
|
77
|
+
# => #<Engine layout="V6", fuel="gasoline">
|
78
|
+
```
|
79
|
+
|
80
|
+
### Equality
|
81
|
+
|
82
|
+
Normal equality methods are here.
|
49
83
|
```ruby
|
50
84
|
e.eql? Engine.new(layout: 'I4') # => false
|
51
85
|
e == Engine.new(layout: 'V6', fuel: 'diesel') # => true
|
52
86
|
```
|
53
87
|
|
88
|
+
### Serialization
|
89
|
+
|
90
|
+
JSON serialization is ready after you require it.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
require 'json'
|
94
|
+
e.to_json
|
95
|
+
# => "{\"layout\":\"V6\",\"fuel\":\"gasoline\"}"
|
96
|
+
```
|
97
|
+
|
98
|
+
### Overriding
|
99
|
+
|
100
|
+
#### Getters/Readers
|
101
|
+
If you want to customize the way an attribute is read, just override the method
|
102
|
+
like you would any accessor. You can access the raw value through either the instance variable,
|
103
|
+
`read_attribute`, or `super`.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
class Taco < Liner.new(:filling)
|
107
|
+
def filling
|
108
|
+
if read_liner(:filling) == 'ground beef'
|
109
|
+
'Steak'
|
110
|
+
elsif @filling == 'unknown fish'
|
111
|
+
'Atlantic Cod'
|
112
|
+
else
|
113
|
+
super()
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
Overridden getters will take precedence for the other features. This
|
120
|
+
is probably desirable, just don't be surprised by it.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
taco = Taco.new("ground beef")
|
124
|
+
# => #<Taco filling="Steak">
|
125
|
+
taco[:filling] = 'unknown fish'
|
126
|
+
# => 'unknown fish'
|
127
|
+
taco.liner
|
128
|
+
# => {:filling=>"Atlantic Cod"}
|
129
|
+
```
|
130
|
+
|
131
|
+
#### Setters/Writers
|
132
|
+
It's the same scenario for customizing the writer. Set the real value
|
133
|
+
through the instance variable, `write_attribute`, or `super`.
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
class Bacon < Liner.new(:is_good)
|
137
|
+
def is_good=(good)
|
138
|
+
@is_good = true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
Again, the overridden method takes precendence, even with writers.
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
generic_bacon = Bacon.new
|
147
|
+
generic_bacon[:is_good] = false
|
148
|
+
# => true
|
149
|
+
```
|
150
|
+
|
151
|
+
### Inheritance
|
152
|
+
|
153
|
+
Inheritance of Liner classes works like any other Ruby class, but you can tack
|
154
|
+
on extra attributes to child classes if you like.
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
class Instrument
|
158
|
+
liner :key
|
159
|
+
end
|
160
|
+
|
161
|
+
class Guitar < Instrument
|
162
|
+
liner :strings
|
163
|
+
end
|
164
|
+
|
165
|
+
Guitar.new('C', 6)
|
166
|
+
# => #<Guitar key="C", strings=6>
|
167
|
+
```
|
168
|
+
|
54
169
|
## Installation
|
55
170
|
|
56
171
|
Add this line to your application's Gemfile:
|
data/lib/ext/class.rb
CHANGED
data/lib/liner.rb
CHANGED
@@ -7,6 +7,8 @@ require 'liner/serializable'
|
|
7
7
|
require 'ext/class'
|
8
8
|
|
9
9
|
module Liner
|
10
|
+
# include all submodules when included
|
11
|
+
# @api public
|
10
12
|
def self.included(base)
|
11
13
|
[Base, Hashable, Equalizable, Inspectable, Serializable].each do |mod|
|
12
14
|
base.send :include, mod
|
@@ -14,24 +16,39 @@ module Liner
|
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
19
|
+
# Setup an anonymous class with liner keys
|
20
|
+
# @param keys [Array] An array of symbols or strings which will serve as attributes
|
21
|
+
# @return [Class]
|
22
|
+
# @example Liner.new(:foo) # => #<Class:0x007fd0993bab98>
|
23
|
+
# @api public
|
17
24
|
def Liner.new(*keys)
|
18
|
-
apply Class.new, *keys
|
25
|
+
apply! Class.new, *keys
|
19
26
|
end
|
20
27
|
|
21
|
-
|
28
|
+
# Apply a liner to a given class
|
29
|
+
# @param base [Class] A class to add a liner to
|
30
|
+
# @param keys [Array] An array of symbols or strings which will serve as attributes
|
31
|
+
# @return [Class] The class with a liner installed
|
32
|
+
# @api public
|
33
|
+
def Liner.apply!(base, *keys)
|
22
34
|
keys = keys.map(&:to_sym).uniq.freeze
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
35
|
+
|
36
|
+
base.send(:define_method, :liner_keys) do
|
37
|
+
begin
|
38
|
+
(super() + keys).uniq
|
39
|
+
rescue NoMethodError
|
40
|
+
keys
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
base.send :include, Liner unless base < Liner
|
45
|
+
|
46
|
+
keys.each do |key|
|
47
|
+
unless base.method_defined? key
|
48
|
+
base.send(:define_method, key){ liner_get key }
|
30
49
|
end
|
31
|
-
|
32
|
-
|
33
|
-
define_method(key){ self[key] }
|
34
|
-
define_method("#{key}="){ |value| self[key] = value }
|
50
|
+
unless base.method_defined? "#{key}="
|
51
|
+
base.send(:define_method, "#{key}="){ |value| liner_set key, value }
|
35
52
|
end
|
36
53
|
end
|
37
54
|
base
|
data/lib/liner/base.rb
CHANGED
@@ -5,9 +5,31 @@ module Liner
|
|
5
5
|
self.liner = args.first
|
6
6
|
elsif args.count >= 1 && args.count <= liner_keys.count
|
7
7
|
self.liner_values = args
|
8
|
-
elsif !args.empty?
|
9
|
-
raise ArgumentError, "Liner doesn't know how to initialize with `#{args}`."
|
10
8
|
end
|
11
9
|
end
|
12
10
|
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def liner_get(key)
|
15
|
+
key = key.to_sym
|
16
|
+
with_valid_attribute(key) do
|
17
|
+
instance_variable_get "@#{key}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def liner_set(key, value)
|
22
|
+
key = key.to_sym
|
23
|
+
with_valid_attribute(key) do
|
24
|
+
instance_variable_set "@#{key}", value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def with_valid_attribute(key, &block)
|
29
|
+
if liner_keys.include?(key)
|
30
|
+
yield
|
31
|
+
else
|
32
|
+
raise ArgumentError, "Invalid liner attribute: '#{key}'"
|
33
|
+
end
|
34
|
+
end
|
13
35
|
end
|
data/lib/liner/hashable.rb
CHANGED
@@ -1,30 +1,29 @@
|
|
1
1
|
module Liner
|
2
2
|
module Hashable
|
3
3
|
|
4
|
-
def
|
5
|
-
|
4
|
+
def [](key)
|
5
|
+
send key.to_sym
|
6
|
+
rescue NoMethodError
|
7
|
+
liner_get key
|
6
8
|
end
|
7
9
|
|
8
|
-
def
|
9
|
-
|
10
|
+
def []=(key,value)
|
11
|
+
send :"#{key}=", value
|
12
|
+
rescue NoMethodError
|
13
|
+
liner_set key, value
|
10
14
|
end
|
11
15
|
|
12
|
-
def
|
13
|
-
|
16
|
+
def liner
|
17
|
+
liner_keys.inject({}) { |h,k| h[k] = self[k]; h }.freeze
|
14
18
|
end
|
15
19
|
|
16
|
-
def
|
17
|
-
|
18
|
-
if liner_keys.include?(key)
|
19
|
-
liner[key] = value
|
20
|
-
else
|
21
|
-
raise ArgumentError, "Invalid liner attribute: '#{key}'."
|
22
|
-
end
|
20
|
+
def liner=(hash)
|
21
|
+
hash.each { |k,v| self[k] = hash[k] }
|
23
22
|
end
|
24
23
|
|
25
24
|
def liner_values=(values)
|
26
|
-
values.each_with_index do |
|
27
|
-
self[liner_keys[i]] =
|
25
|
+
values.each_with_index do |value, i|
|
26
|
+
self[liner_keys[i]] = value
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
data/lib/liner/version.rb
CHANGED
data/liner.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Liner::VERSION
|
9
9
|
spec.authors = ["Josh Lewis"]
|
10
10
|
spec.email = ["josh.w.lewis@gmail.com"]
|
11
|
-
spec.description = %q{A liner for Ruby objects. Add attribute, inspection, and equality methods.}
|
12
|
-
spec.summary = %q{
|
11
|
+
spec.description = %q{A liner for Ruby objects. Add attribute, inspection, serialization, and equality methods.}
|
12
|
+
spec.summary = %q{Liner is a lightweight library designed to enhance simple classes with a few conveniences and idioms while staying out of your way.}
|
13
13
|
spec.homepage = "https://github.com/joshwlewis/liner"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -21,4 +21,5 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
spec.add_development_dependency "minitest"
|
24
|
+
spec.add_development_dependency "coveralls"
|
24
25
|
end
|
data/test/liner/hashable_test.rb
CHANGED
@@ -6,6 +6,10 @@ describe Liner::Hashable do
|
|
6
6
|
subject[:yeast].must_equal nil
|
7
7
|
end
|
8
8
|
|
9
|
+
it "[] should not read invalid attributes" do
|
10
|
+
->{ subject[:foo] }.must_raise ArgumentError
|
11
|
+
end
|
12
|
+
|
9
13
|
it "#[]= should set attributes" do
|
10
14
|
subject[:yeast]= "Top Fermenting"
|
11
15
|
subject.yeast.must_equal "Top Fermenting"
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: liner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Lewis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,7 +52,22 @@ dependencies:
|
|
52
52
|
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coveralls
|
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
|
+
description: A liner for Ruby objects. Add attribute, inspection, serialization, and
|
70
|
+
equality methods.
|
56
71
|
email:
|
57
72
|
- josh.w.lewis@gmail.com
|
58
73
|
executables: []
|
@@ -60,6 +75,7 @@ extensions: []
|
|
60
75
|
extra_rdoc_files: []
|
61
76
|
files:
|
62
77
|
- .gitignore
|
78
|
+
- .travis.yml
|
63
79
|
- Gemfile
|
64
80
|
- LICENSE.txt
|
65
81
|
- README.md
|
@@ -103,7 +119,8 @@ rubyforge_project:
|
|
103
119
|
rubygems_version: 2.2.1
|
104
120
|
signing_key:
|
105
121
|
specification_version: 4
|
106
|
-
summary:
|
122
|
+
summary: Liner is a lightweight library designed to enhance simple classes with a
|
123
|
+
few conveniences and idioms while staying out of your way.
|
107
124
|
test_files:
|
108
125
|
- test/liner/base_test.rb
|
109
126
|
- test/liner/equalizable_test.rb
|
@@ -112,3 +129,4 @@ test_files:
|
|
112
129
|
- test/liner/serializable_test.rb
|
113
130
|
- test/liner_test.rb
|
114
131
|
- test/test_helper.rb
|
132
|
+
has_rdoc:
|