liner 0.1.2 → 0.2.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: 1031b1dc95208b1a8692204114af88b6e46ee907
4
- data.tar.gz: f4a3cb0860e01d58d748bf0b000ef1e38b8a6290
3
+ metadata.gz: 53f068a96a64299ca295a0c1821a5232a4ec2618
4
+ data.tar.gz: 459fd2b8e24e184a5437744fa1ae3701c384d609
5
5
  SHA512:
6
- metadata.gz: 0cd932e7fddb88187281890814b89af03ef3c01fc0bcc635fa3f6f2d3614c624776a74f2ef7308c9cee013d004b7df82214f4483931921871af53ba571e9257f
7
- data.tar.gz: 7722ba0e233b9ad646ec73be8fe5192c154d3442be4ff2f01138912f1648f96cdbd3004caec1851cc19ba7edabcd0bbe5d52bdbd3e4551528e0c45c8627832c5
6
+ metadata.gz: 98f7de6a0c3580a6dd7c8774aa7b427b7819c30a28ad1dce9fdfd362fd3c6a9742df59f2c9a0b64508e943a802a3fa422c3f442c6529827d7acf5dab9e943bd1
7
+ data.tar.gz: 7d8e902c6662b26f751bee45f120855c21e3a300a66532fe536d4be439f5063745a352691f97788cd0461086a88bba3b6ff269327354d75c0761b381cf29abf3
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
data/README.md CHANGED
@@ -1,27 +1,40 @@
1
1
  # Liner
2
+ [![Build Status](https://travis-ci.org/joshwlewis/liner.png?branch=master)](https://travis-ci.org/joshwlewis/liner)
3
+ [![Coverage Status](https://coveralls.io/repos/joshwlewis/liner/badge.png?branch=master)](https://coveralls.io/r/joshwlewis/liner?branch=master)
4
+ [![Gem Version](https://badge.fury.io/rb/liner.png)](http://badge.fury.io/rb/liner)
5
+ [![Dependency Status](https://gemnasium.com/joshwlewis/liner.png)](https://gemnasium.com/joshwlewis/liner)
6
+ [![Code Climate](https://codeclimate.com/github/joshwlewis/liner.png)](https://codeclimate.com/github/joshwlewis/liner)
2
7
 
3
- Lay a liner for your Ruby classes. Liner is designed to enhance simple classes
4
- with some common idioms.
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
- Equality methods are also availble.
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:
@@ -1,5 +1,5 @@
1
1
  Class.class_eval do
2
2
  def liner(*keys)
3
- Liner.apply self, *keys
3
+ Liner.apply! self, *keys
4
4
  end
5
5
  end
@@ -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
- def Liner.apply(base, *keys)
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
- base.class_eval do
24
- define_method :liner_keys do
25
- begin
26
- (super() + keys).uniq
27
- rescue NoMethodError
28
- keys
29
- end
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
- include Liner
32
- keys.each do |key|
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
@@ -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
@@ -1,30 +1,29 @@
1
1
  module Liner
2
2
  module Hashable
3
3
 
4
- def liner
5
- @liner ||= liner_keys.inject({}) { |h,k| h[k]=nil; h }
4
+ def [](key)
5
+ send key.to_sym
6
+ rescue NoMethodError
7
+ liner_get key
6
8
  end
7
9
 
8
- def liner=(hash)
9
- hash.each { |k,v| self[k] = hash[k] }
10
+ def []=(key,value)
11
+ send :"#{key}=", value
12
+ rescue NoMethodError
13
+ liner_set key, value
10
14
  end
11
15
 
12
- def [](key)
13
- liner[key.to_sym]
16
+ def liner
17
+ liner_keys.inject({}) { |h,k| h[k] = self[k]; h }.freeze
14
18
  end
15
19
 
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
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 |v,i|
27
- self[liner_keys[i]] = v
25
+ values.each_with_index do |value, i|
26
+ self[liner_keys[i]] = value
28
27
  end
29
28
  end
30
29
 
@@ -1,3 +1,3 @@
1
1
  module Liner
2
- VERSION = '0.1.2'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -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{A liner for Ruby objects. Add attribute, inspection, and equality methods.}
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
@@ -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"
@@ -1,8 +1,10 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
1
4
  require 'minitest/autorun'
2
5
  require 'minitest/pride'
3
6
  require 'liner'
4
7
 
5
-
6
8
  # create some dummy classes to test against with each of the supported usages.
7
9
 
8
10
  Beer = Liner.new :hops, :yeast
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.1.2
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-02 00:00:00.000000000 Z
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
- description: A liner for Ruby objects. Add attribute, inspection, and equality methods.
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: A liner for Ruby objects. Add attribute, inspection, and equality methods.
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: