attire 1.1.0 → 2.0.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/README.md +24 -60
- data/lib/attire.rb +2 -24
- data/lib/attire/initializer.rb +49 -0
- data/lib/attire/method_object.rb +12 -0
- metadata +5 -9
- data/lib/attire/attr_init.rb +0 -24
- data/lib/attire/attr_init/arguments.rb +0 -55
- data/lib/attire/attr_init/arguments_checker.rb +0 -66
- data/lib/attire/attr_init/instance_methods.rb +0 -37
- data/lib/attire/attr_init/values_matcher.rb +0 -42
- data/lib/attire/core_ext/duplicable.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e47510ce77fba871c171411ee89810f79bbe8231
|
4
|
+
data.tar.gz: 1ed7fbacff39b565ce85235d25e376941006021f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 08e1829aecf20e6405dbcc3f2189a097f13cf8368de2770095857fd6968d02491106f0c52fba094b9d6c5a8cd50f8f4f885c11d1391440f8acd92fa5c2590d5c
|
7
|
+
data.tar.gz: 1c7084866f5e17483c32ed4fa9a20810d57b1aa5904909dd2e2712e369d85a9821e6addbc3b6dea03717c58c4e8d6215ca6d39e0a589ed6b17b1cc471a0a1203
|
data/README.md
CHANGED
@@ -3,87 +3,53 @@
|
|
3
3
|
[](https://travis-ci.org/mushishi78/attire)
|
4
4
|
[](http://badge.fury.io/rb/attire)
|
5
5
|
|
6
|
-
|
6
|
+
Mixins to remove some boiler plate in defining classes.
|
7
7
|
|
8
|
-
|
8
|
+
**N.B. This is the README for version 2.0.0. Major changes have been made. For previous versions please consult the tagged commit.**
|
9
9
|
|
10
|
-
|
11
|
-
attr_init :foo, :bar, fizz: 15, pop: nil
|
12
|
-
```
|
10
|
+
## Initializer
|
13
11
|
|
14
|
-
|
12
|
+
`Attire::Initializer` extends a subsequent initialize method so that all it's parameters are assigned to instance variables and they can all be reached from private getters. For example:
|
15
13
|
|
16
14
|
``` ruby
|
17
|
-
|
18
|
-
@foo = foo
|
19
|
-
@bar = bar
|
20
|
-
@fizz = opts[:fizz]
|
21
|
-
@pop = opts[:pop]
|
22
|
-
end
|
15
|
+
require 'attire'
|
23
16
|
|
24
|
-
|
17
|
+
class MyClass
|
18
|
+
extend Attire::Initializer
|
25
19
|
|
26
|
-
|
20
|
+
def initialize(foo:, bar: 24)
|
21
|
+
@bar = bar * 2
|
22
|
+
end
|
27
23
|
|
28
|
-
def
|
29
|
-
|
24
|
+
def result
|
25
|
+
foo + bar
|
26
|
+
end
|
30
27
|
end
|
31
|
-
```
|
32
28
|
|
33
|
-
|
34
|
-
|
35
|
-
``` ruby
|
36
|
-
attr_init :'opts = {}', :'*args', :'&block'
|
29
|
+
my_instance = MyClass.new(foo: 50)
|
30
|
+
my_instance.result # 98
|
37
31
|
```
|
38
32
|
|
39
|
-
|
40
|
-
|
41
|
-
``` ruby
|
42
|
-
attr_init :foo do
|
43
|
-
@foo = foo ** 2
|
44
|
-
end
|
45
|
-
```
|
46
|
-
|
47
|
-
## attr_method
|
48
|
-
|
49
|
-
``` ruby
|
50
|
-
attr_method :select, :bar
|
51
|
-
```
|
33
|
+
## MethodObject
|
52
34
|
|
53
|
-
|
54
|
-
|
55
|
-
``` ruby
|
56
|
-
def self.select(*args, &block)
|
57
|
-
new(*args, &block).select
|
58
|
-
end
|
59
|
-
|
60
|
-
attr_init :bar
|
61
|
-
```
|
62
|
-
|
63
|
-
This is useful for method objects/use cases:
|
35
|
+
`Attire::MethodObject` does the same as `Attire::Initializer` but it also adds a singleton method that creates an instance and then calls an instance method. This is useful for objects that are designed to do one task. For example:
|
64
36
|
|
65
37
|
``` ruby
|
66
38
|
class CheeseSpreader
|
67
|
-
|
39
|
+
extend Attire::MethodObject.new(:spread)
|
40
|
+
|
41
|
+
def initialize(cheese, cracker: Jacobs.new)
|
42
|
+
end
|
68
43
|
|
69
44
|
def spread
|
70
|
-
cracker = crackers_class.new
|
71
45
|
cracker.spreads << cheese
|
72
46
|
cracker
|
73
47
|
end
|
74
48
|
end
|
75
49
|
|
76
|
-
CheeseSpreader.spread(roquefort)
|
50
|
+
CheeseSpreader.spread(:roquefort)
|
77
51
|
```
|
78
52
|
|
79
|
-
## attr_query
|
80
|
-
|
81
|
-
``` ruby
|
82
|
-
attr_query :foo?
|
83
|
-
```
|
84
|
-
|
85
|
-
Defines query `#foo?`, which is true if `foo` is truthy.
|
86
|
-
|
87
53
|
## Installation
|
88
54
|
|
89
55
|
Add to Gemfile:
|
@@ -92,11 +58,9 @@ Add to Gemfile:
|
|
92
58
|
gem 'attire'
|
93
59
|
```
|
94
60
|
|
95
|
-
|
61
|
+
## Inspirations
|
96
62
|
|
97
|
-
|
98
|
-
require 'attire'
|
99
|
-
```
|
63
|
+
* [attr_extras](https://github.com/barsoom/attr_extras).
|
100
64
|
|
101
65
|
## Contributing
|
102
66
|
|
data/lib/attire.rb
CHANGED
@@ -1,24 +1,2 @@
|
|
1
|
-
require 'attire/
|
2
|
-
|
3
|
-
module Attire
|
4
|
-
def attr_query(*names)
|
5
|
-
names.each do |name|
|
6
|
-
name = name.to_s
|
7
|
-
fail ArgumentError, "`#{name}?`, not `#{name}`." unless name.end_with?('?')
|
8
|
-
define_method(name) { !!send(name.chop) }
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def attr_init(*args, &block)
|
13
|
-
include AttrInit.new(args, block)
|
14
|
-
end
|
15
|
-
|
16
|
-
def attr_method(verb, *args, &block)
|
17
|
-
define_singleton_method(verb) { |*a, &b| new(*a, &b).send(verb) }
|
18
|
-
attr_init(*args, &block)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class Module
|
23
|
-
include Attire
|
24
|
-
end
|
1
|
+
require 'attire/initializer'
|
2
|
+
require 'attire/method_object'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Attire
|
2
|
+
module Initializer
|
3
|
+
def self.extended(base)
|
4
|
+
base.class.instance_variable_set(:@_added, false)
|
5
|
+
end
|
6
|
+
|
7
|
+
def method_added(method_name)
|
8
|
+
return super unless method_name == :initialize && !added?
|
9
|
+
method = instance_method(:initialize)
|
10
|
+
names = method.parameters.map(&:last)
|
11
|
+
add_initialize(method, names)
|
12
|
+
add_getters(names)
|
13
|
+
self.added = true
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def added?
|
20
|
+
self.class.instance_variable_get(:@_added)
|
21
|
+
end
|
22
|
+
|
23
|
+
def added=(added)
|
24
|
+
self.class.instance_variable_set(:@_added, added)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_initialize(method, names)
|
28
|
+
initialize_line = initialize_line(method)
|
29
|
+
set_ivars = names.map { |name| "@#{name} = #{name}\n" }.join
|
30
|
+
|
31
|
+
initializer = Module.new do
|
32
|
+
class_eval "#{initialize_line}#{set_ivars}super\nend\n"
|
33
|
+
end
|
34
|
+
prepend initializer
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize_line(method)
|
38
|
+
file, endline = *method.source_location
|
39
|
+
File.readlines(file)[0..endline].reverse.each do |line|
|
40
|
+
return line if line.include?('initialize')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_getters(names)
|
45
|
+
attr_reader(*names)
|
46
|
+
private(*names)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'initializer'
|
2
|
+
|
3
|
+
module Attire
|
4
|
+
module MethodObject
|
5
|
+
def self.new(verb)
|
6
|
+
Module.new do
|
7
|
+
define_singleton_method(:extended) { |base| base.extend Initializer }
|
8
|
+
define_method(verb) { |*a, **k, &b| new(*a, **k, &b).send(verb) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max White
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -39,12 +39,8 @@ files:
|
|
39
39
|
- LICENSE.txt
|
40
40
|
- README.md
|
41
41
|
- lib/attire.rb
|
42
|
-
- lib/attire/
|
43
|
-
- lib/attire/
|
44
|
-
- lib/attire/attr_init/arguments_checker.rb
|
45
|
-
- lib/attire/attr_init/instance_methods.rb
|
46
|
-
- lib/attire/attr_init/values_matcher.rb
|
47
|
-
- lib/attire/core_ext/duplicable.rb
|
42
|
+
- lib/attire/initializer.rb
|
43
|
+
- lib/attire/method_object.rb
|
48
44
|
homepage: https://github.com/mushishi78/attire
|
49
45
|
licenses:
|
50
46
|
- MIT
|
@@ -68,5 +64,5 @@ rubyforge_project:
|
|
68
64
|
rubygems_version: 2.2.2
|
69
65
|
signing_key:
|
70
66
|
specification_version: 4
|
71
|
-
summary:
|
67
|
+
summary: Mixins to remove some boiler plate in defining classes.
|
72
68
|
test_files: []
|
data/lib/attire/attr_init.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'attire/attr_init/arguments_checker'
|
2
|
-
require 'attire/attr_init/arguments'
|
3
|
-
require 'attire/attr_init/values_matcher'
|
4
|
-
require 'attire/attr_init/instance_methods'
|
5
|
-
|
6
|
-
module Attire
|
7
|
-
module AttrInit
|
8
|
-
def self.new(args, after_block)
|
9
|
-
ArgumentsChecker.check(args)
|
10
|
-
arguments = Arguments.new(args)
|
11
|
-
values_matcher = ValuesMatcher.new(arguments)
|
12
|
-
getters, defaults = arguments.getters, arguments.defaults
|
13
|
-
|
14
|
-
Module.new do
|
15
|
-
include InstanceMethods
|
16
|
-
define_method(:_arguments) { arguments }
|
17
|
-
define_method(:_after_block) { after_block }
|
18
|
-
define_method(:_values_matcher) { values_matcher }
|
19
|
-
getters.each { |n| define_method(n) { _get_attribute(n, defaults[n]) } }
|
20
|
-
private(*getters)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'attire/core_ext/duplicable'
|
2
|
-
|
3
|
-
module Attire
|
4
|
-
module AttrInit
|
5
|
-
class Arguments
|
6
|
-
def initialize(arguments)
|
7
|
-
@block = last_argument_with_prefix(arguments, '&')
|
8
|
-
@splat = last_argument_with_prefix(arguments, '*')
|
9
|
-
@names, @defaults = [], {}
|
10
|
-
arguments.each { |arg| extract_argument(arg) }
|
11
|
-
@arity_range = (min_arity..max_arity)
|
12
|
-
@getters = (names.flatten + [splat, block]).compact
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_reader :names, :splat, :block, :defaults, :arity_range, :getters
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def last_argument_with_prefix(arguments, prefix)
|
20
|
-
return unless arguments.last.to_s.start_with?(prefix)
|
21
|
-
arguments.pop.to_s[1..-1]
|
22
|
-
end
|
23
|
-
|
24
|
-
def extract_argument(arg)
|
25
|
-
return extract_hash(arg) if arg.is_a?(Hash)
|
26
|
-
return extract_optional(arg) if arg.to_s.include?('=')
|
27
|
-
extract_required(arg)
|
28
|
-
end
|
29
|
-
|
30
|
-
def extract_hash(hash)
|
31
|
-
names << hash.keys
|
32
|
-
defaults.merge!(hash)
|
33
|
-
end
|
34
|
-
|
35
|
-
def extract_optional(arg)
|
36
|
-
name, default = arg.to_s.split('=').map(&:strip)
|
37
|
-
names << name
|
38
|
-
defaults[name] = eval(default)
|
39
|
-
end
|
40
|
-
|
41
|
-
def extract_required(arg)
|
42
|
-
names << arg
|
43
|
-
@min_arity = names.length
|
44
|
-
end
|
45
|
-
|
46
|
-
def min_arity
|
47
|
-
@min_arity ||= 0
|
48
|
-
end
|
49
|
-
|
50
|
-
def max_arity
|
51
|
-
splat ? Float::INFINITY : names.length
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
module Attire
|
2
|
-
module AttrInit
|
3
|
-
class ArgumentsChecker
|
4
|
-
def self.check(arguments)
|
5
|
-
new.check(arguments)
|
6
|
-
end
|
7
|
-
|
8
|
-
def check(arguments)
|
9
|
-
arguments.reverse.each_with_index do |arg, i|
|
10
|
-
@arg, @i = arg, i
|
11
|
-
type_check
|
12
|
-
block_check
|
13
|
-
splat_check
|
14
|
-
required_after_optional_check
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
attr_reader :arg, :i
|
21
|
-
|
22
|
-
TYPES = [Symbol, String, Hash]
|
23
|
-
|
24
|
-
def type_check
|
25
|
-
return if TYPES.include?(arg.class)
|
26
|
-
fail ArgumentError, 'Must be Symbol, String or Hash.'
|
27
|
-
end
|
28
|
-
|
29
|
-
def block_check
|
30
|
-
return unless block?
|
31
|
-
fail ArgumentError, 'Block arguments must be last' unless i == 0
|
32
|
-
@has_block = true
|
33
|
-
end
|
34
|
-
|
35
|
-
def splat_check
|
36
|
-
return unless splat?
|
37
|
-
return if i == (@has_block ? 1 : 0)
|
38
|
-
msg = 'Splat arguments must come after required and optional arguments'
|
39
|
-
fail ArgumentError, msg
|
40
|
-
end
|
41
|
-
|
42
|
-
def required_after_optional_check
|
43
|
-
return if block? || splat? || hash?
|
44
|
-
return @has_requireds = true unless optional?
|
45
|
-
return unless @has_requireds
|
46
|
-
fail ArgumentError, 'Required arguments must come before optional'
|
47
|
-
end
|
48
|
-
|
49
|
-
def block?
|
50
|
-
arg.to_s.start_with?('&')
|
51
|
-
end
|
52
|
-
|
53
|
-
def splat?
|
54
|
-
arg.to_s.start_with?('*')
|
55
|
-
end
|
56
|
-
|
57
|
-
def hash?
|
58
|
-
arg.is_a?(Hash)
|
59
|
-
end
|
60
|
-
|
61
|
-
def optional?
|
62
|
-
arg.to_s.include?('=')
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module Attire
|
2
|
-
module AttrInit
|
3
|
-
module InstanceMethods
|
4
|
-
def initialize(*values, &value_block)
|
5
|
-
_arity_check(values)
|
6
|
-
_match(values, value_block).each { |k, v| instance_variable_set("@#{k}", v) }
|
7
|
-
instance_exec(&_after_block) if _after_block
|
8
|
-
end
|
9
|
-
|
10
|
-
private
|
11
|
-
|
12
|
-
def _arity_check(values)
|
13
|
-
return if _arity_range.include?(values.length)
|
14
|
-
msg = "wrong number of arguments (#{values.length} for #{_arity_range})"
|
15
|
-
fail ArgumentError, msg
|
16
|
-
end
|
17
|
-
|
18
|
-
def _get_attribute(name, default)
|
19
|
-
value = instance_variable_get("@#{name}")
|
20
|
-
return value unless value.nil? && !default.nil?
|
21
|
-
instance_variable_set("@#{name}", _duped_default(default))
|
22
|
-
end
|
23
|
-
|
24
|
-
def _duped_default(default)
|
25
|
-
default.duplicable? ? default.dup : default
|
26
|
-
end
|
27
|
-
|
28
|
-
def _match(*args)
|
29
|
-
_values_matcher.match(*args)
|
30
|
-
end
|
31
|
-
|
32
|
-
def _arity_range
|
33
|
-
_arguments.arity_range
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
|
-
module Attire
|
4
|
-
module AttrInit
|
5
|
-
class ValuesMatcher
|
6
|
-
extend Forwardable
|
7
|
-
|
8
|
-
def initialize(arguments)
|
9
|
-
@arguments = arguments
|
10
|
-
end
|
11
|
-
|
12
|
-
def match(values, value_block)
|
13
|
-
@matched = {}
|
14
|
-
names.zip(values) { |n, v| n.is_a?(Array) ? set_from_hash(v) : set(n, v) }
|
15
|
-
set_splat(values)
|
16
|
-
set_block(value_block)
|
17
|
-
matched
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
attr_reader :arguments, :matched
|
23
|
-
def_delegators :arguments, :names, :splat, :block
|
24
|
-
|
25
|
-
def set(name, value)
|
26
|
-
matched[name] = value
|
27
|
-
end
|
28
|
-
|
29
|
-
def set_from_hash(values)
|
30
|
-
matched.merge!(values || {})
|
31
|
-
end
|
32
|
-
|
33
|
-
def set_splat(values)
|
34
|
-
matched[splat] = values[names.length..-1] || [] if splat
|
35
|
-
end
|
36
|
-
|
37
|
-
def set_block(value_block)
|
38
|
-
matched[block] = value_block if block
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
class Object
|
2
|
-
def duplicable?
|
3
|
-
true
|
4
|
-
end
|
5
|
-
end
|
6
|
-
|
7
|
-
class NilClass
|
8
|
-
def duplicable?
|
9
|
-
false
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class FalseClass
|
14
|
-
def duplicable?
|
15
|
-
false
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class TrueClass
|
20
|
-
def duplicable?
|
21
|
-
false
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class Symbol
|
26
|
-
def duplicable?
|
27
|
-
false
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class Numeric
|
32
|
-
def duplicable?
|
33
|
-
false
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
require 'bigdecimal'
|
38
|
-
class BigDecimal
|
39
|
-
def duplicable?
|
40
|
-
true
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class Method
|
45
|
-
def duplicable?
|
46
|
-
false
|
47
|
-
end
|
48
|
-
end
|