attire 0.1.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +107 -93
- data/lib/attire/attr_init/arguments.rb +57 -0
- data/lib/attire/attr_init/arguments_checker.rb +66 -0
- data/lib/attire/attr_init/initializer.rb +30 -0
- data/lib/attire/attr_init/values_matcher.rb +42 -0
- data/lib/attire/attr_init.rb +26 -82
- data/lib/attire.rb +24 -24
- metadata +7 -4
- data/lib/attire/initializer.rb +0 -92
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1e1fc1f22a2213695656d10b09d2de54e340910
|
4
|
+
data.tar.gz: 0e10d06cf3402de661391eb894c5127f6a9f56fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8878fced254c26d7f4520bb99547d88c96b5355b79200b8e3ace0c47e03c3c1e26c64b4ecfc435184c209138ffecb1f11c38876f249f33417a03abce178f7def
|
7
|
+
data.tar.gz: 76646d629df750287941eaad2e57a3884f236be29a0c77bc66eb7bd0bcc08730def009c0dbccefb66b9c0e32350cab641c07d176ee7b7e294b276f93dd427421
|
data/README.md
CHANGED
@@ -1,93 +1,107 @@
|
|
1
|
-
# Attire
|
2
|
-
|
3
|
-
[![Build Status](https://travis-ci.org/mushishi78/attire.svg?branch=master)](https://travis-ci.org/mushishi78/attire)
|
4
|
-
[![Gem Version](https://badge.fury.io/rb/attire.svg)](http://badge.fury.io/rb/attire)
|
5
|
-
|
6
|
-
Convenience methods to remove some boiler plate in defining classes. Inspired by [attr_extras](https://github.com/barsoom/attr_extras).
|
7
|
-
|
8
|
-
##
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
```
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
``` ruby
|
36
|
-
attr_init :
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
```
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
```
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
``` ruby
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
CheeseSpreader
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
```
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
```
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
##
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
1
|
+
# Attire
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/mushishi78/attire.svg?branch=master)](https://travis-ci.org/mushishi78/attire)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/attire.svg)](http://badge.fury.io/rb/attire)
|
5
|
+
|
6
|
+
Convenience methods to remove some boiler plate in defining classes. Inspired by [attr_extras](https://github.com/barsoom/attr_extras).
|
7
|
+
|
8
|
+
## attr_init
|
9
|
+
|
10
|
+
``` ruby
|
11
|
+
attr_init :foo, :bar, fizz: 15, pop: nil
|
12
|
+
```
|
13
|
+
|
14
|
+
Defines the following:
|
15
|
+
|
16
|
+
``` ruby
|
17
|
+
def initialize(foo, bar, opts = {})
|
18
|
+
@foo = foo
|
19
|
+
@bar = bar
|
20
|
+
@fizz = opts[:fizz]
|
21
|
+
@pop = opts[:pop]
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :foo, :bar, :pop
|
27
|
+
|
28
|
+
def fizz
|
29
|
+
@fizz ||= 15
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
Optional, splat and blocks arguments can also be defined:
|
34
|
+
|
35
|
+
``` ruby
|
36
|
+
attr_init :'opts = {}', :'*args', :'&block'
|
37
|
+
```
|
38
|
+
|
39
|
+
If a block is provided, it will be evaluated after initialization:
|
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
|
+
```
|
52
|
+
|
53
|
+
Defines the following:
|
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:
|
64
|
+
|
65
|
+
``` ruby
|
66
|
+
class CheeseSpreader
|
67
|
+
attr_method :spread, :cheese, crackers_class: Jacobs
|
68
|
+
|
69
|
+
def spread
|
70
|
+
cracker = crackers_class.new
|
71
|
+
cracker.spreads << cheese
|
72
|
+
cracker
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
CheeseSpreader.spread(roquefort)
|
77
|
+
```
|
78
|
+
|
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
|
+
## Installation
|
88
|
+
|
89
|
+
Add to Gemfile:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
gem 'attire'
|
93
|
+
```
|
94
|
+
|
95
|
+
Require library:
|
96
|
+
|
97
|
+
``` ruby
|
98
|
+
require 'attire'
|
99
|
+
```
|
100
|
+
|
101
|
+
## Contributing
|
102
|
+
|
103
|
+
1. Fork it ( https://github.com/[my-github-username]/attire/fork )
|
104
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
105
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
106
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
107
|
+
5. Create a new Pull Request
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'attire/core_ext/duplicable'
|
2
|
+
require_relative 'arguments_checker'
|
3
|
+
|
4
|
+
module Attire
|
5
|
+
module AttrInit
|
6
|
+
class Arguments
|
7
|
+
def initialize(arguments)
|
8
|
+
ArgumentsChecker.check(arguments)
|
9
|
+
@block = last_argument_with_prefix(arguments, '&')
|
10
|
+
@splat = last_argument_with_prefix(arguments, '*')
|
11
|
+
@names, @defaults = [], {}
|
12
|
+
arguments.each { |arg| extract_argument(arg) }
|
13
|
+
@arity_range = (min_arity..max_arity)
|
14
|
+
@getter_names = (names.flatten + [splat, block]).compact
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :names, :splat, :block, :defaults, :arity_range, :getter_names
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def last_argument_with_prefix(arguments, prefix)
|
22
|
+
return unless arguments.last.to_s.start_with?(prefix)
|
23
|
+
arguments.pop.to_s[1..-1]
|
24
|
+
end
|
25
|
+
|
26
|
+
def extract_argument(arg)
|
27
|
+
return extract_hash(arg) if arg.is_a?(Hash)
|
28
|
+
return extract_optional(arg) if arg.to_s.include?('=')
|
29
|
+
extract_required(arg)
|
30
|
+
end
|
31
|
+
|
32
|
+
def extract_hash(hash)
|
33
|
+
names << hash.keys
|
34
|
+
defaults.merge!(hash)
|
35
|
+
end
|
36
|
+
|
37
|
+
def extract_optional(arg)
|
38
|
+
name, default = arg.to_s.split('=').map(&:strip)
|
39
|
+
names << name
|
40
|
+
defaults[name] = eval(default)
|
41
|
+
end
|
42
|
+
|
43
|
+
def extract_required(arg)
|
44
|
+
names << arg
|
45
|
+
@min_arity = names.length
|
46
|
+
end
|
47
|
+
|
48
|
+
def min_arity
|
49
|
+
@min_arity ||= 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def max_arity
|
53
|
+
splat ? Float::INFINITY : names.length
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,66 @@
|
|
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
|
+
fail ArgumentError, \
|
39
|
+
'Splat arguments must come after required and optional arguments'
|
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
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'values_matcher'
|
2
|
+
|
3
|
+
module Attire
|
4
|
+
module AttrInit
|
5
|
+
class Initializer
|
6
|
+
def initialize(arguments, after_initialize, opts = {})
|
7
|
+
@values_matcher = opts[:values_matcher] || ValuesMatcher.new(arguments)
|
8
|
+
@arity_range = arguments.arity_range
|
9
|
+
@after_initialize = after_initialize
|
10
|
+
end
|
11
|
+
|
12
|
+
def instance_initialize(instance, values, value_block)
|
13
|
+
arity_check(values)
|
14
|
+
values_matcher.match(values, value_block).each do |k, v|
|
15
|
+
instance.instance_variable_set("@#{k}", v)
|
16
|
+
end
|
17
|
+
instance.instance_exec(&after_initialize) if after_initialize
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :values_matcher, :arity_range, :after_initialize
|
23
|
+
|
24
|
+
def arity_check(values)
|
25
|
+
return if arity_range.include?(values.length)
|
26
|
+
fail ArgumentError, "wrong number of arguments (#{values.length} for #{arity_range})"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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
|
data/lib/attire/attr_init.rb
CHANGED
@@ -1,94 +1,38 @@
|
|
1
|
-
require 'attire/
|
1
|
+
require 'attire/attr_init/arguments'
|
2
|
+
require 'attire/attr_init/initializer'
|
2
3
|
|
3
4
|
module Attire
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
def apply
|
14
|
-
type_check
|
15
|
-
extract_splat_and_block_names
|
16
|
-
optional_arguments_check
|
17
|
-
instance_initialize = initializer.method(:instance_initialize)
|
18
|
-
|
19
|
-
klass.send(:define_method, :initialize) do |*values, &value_block|
|
20
|
-
instance_initialize.call(self, values, value_block)
|
5
|
+
module AttrInit
|
6
|
+
class << self
|
7
|
+
def apply(klass, args, after_initialize)
|
8
|
+
arguments = Arguments.new(args)
|
9
|
+
initializer = Initializer.new(arguments, after_initialize)
|
10
|
+
define_initializer(klass, initializer)
|
11
|
+
define_getters(klass, arguments)
|
21
12
|
end
|
22
13
|
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
attr_reader :klass, :names, :splat_name, :block_name, :after_initialize
|
14
|
+
private
|
29
15
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
def extract_splat_and_block_names
|
36
|
-
@block_name = last_name_with_prefix('&')
|
37
|
-
@splat_name = last_name_with_prefix('*')
|
38
|
-
excess_splat_and_block_names_check
|
39
|
-
end
|
40
|
-
|
41
|
-
def initializer
|
42
|
-
Initializer.new(names, splat_name, block_name, after_initialize)
|
43
|
-
end
|
44
|
-
|
45
|
-
def define_getters
|
46
|
-
getter_names.each do |name|
|
47
|
-
klass.send(:define_method, name) { instance_variable_get("@#{name}") }
|
16
|
+
def define_initializer(klass, initializer)
|
17
|
+
klass.send(:define_method, :initialize) do |*values, &value_block|
|
18
|
+
initializer.instance_initialize(self, values, value_block)
|
19
|
+
end
|
48
20
|
end
|
49
|
-
klass.send(:private, *getter_names)
|
50
|
-
end
|
51
21
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
arg
|
22
|
+
def define_getters(klass, arguments)
|
23
|
+
names = arguments.getter_names
|
24
|
+
names.each { |n| define_getter(klass, n, arguments.defaults[n]) }
|
25
|
+
klass.send(:private, *names)
|
57
26
|
end
|
58
|
-
getter_names += [splat_name, block_name]
|
59
|
-
getter_names.flatten.compact
|
60
|
-
end
|
61
|
-
|
62
|
-
def last_name_with_prefix(prefix)
|
63
|
-
without_prefix(names.pop) if last_name_prefix?(prefix)
|
64
|
-
end
|
65
|
-
|
66
|
-
def without_prefix(symbol)
|
67
|
-
symbol.to_s[1..-1].to_sym
|
68
|
-
end
|
69
|
-
|
70
|
-
def last_name_prefix?(prefix)
|
71
|
-
names.last.to_s.start_with?(prefix)
|
72
|
-
end
|
73
27
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
return if names[start..-1].all? { |n| n.is_a?(Hash) || optional?(n) }
|
83
|
-
fail ArgumentError, 'Required arguments must come before optional'
|
84
|
-
end
|
85
|
-
|
86
|
-
def optional?(name)
|
87
|
-
name.to_s.include?('=')
|
88
|
-
end
|
89
|
-
|
90
|
-
def optional_name(name)
|
91
|
-
name.to_s.split('=')[0].strip
|
28
|
+
def define_getter(klass, name, default)
|
29
|
+
klass.send(:define_method, name) do
|
30
|
+
value = instance_variable_get("@#{name}")
|
31
|
+
return value unless value.nil? && !default.nil?
|
32
|
+
default = default.duplicable? ? default.dup : default
|
33
|
+
instance_variable_set("@#{name}", default)
|
34
|
+
end
|
35
|
+
end
|
92
36
|
end
|
93
37
|
end
|
94
38
|
end
|
data/lib/attire.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
require 'attire/attr_init'
|
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(*
|
13
|
-
AttrInit.apply(self,
|
14
|
-
end
|
15
|
-
|
16
|
-
def attr_method(verb, *
|
17
|
-
define_singleton_method(verb) { |*a, &b| new(*a, &b).send(verb) }
|
18
|
-
attr_init(*
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class Module
|
23
|
-
include Attire
|
24
|
-
end
|
1
|
+
require 'attire/attr_init'
|
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
|
+
AttrInit.apply(self, 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
|
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: 0.
|
4
|
+
version: 1.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-02
|
11
|
+
date: 2015-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -40,9 +40,12 @@ files:
|
|
40
40
|
- README.md
|
41
41
|
- lib/attire.rb
|
42
42
|
- lib/attire/attr_init.rb
|
43
|
+
- lib/attire/attr_init/arguments.rb
|
44
|
+
- lib/attire/attr_init/arguments_checker.rb
|
45
|
+
- lib/attire/attr_init/initializer.rb
|
46
|
+
- lib/attire/attr_init/values_matcher.rb
|
43
47
|
- lib/attire/core_ext/duplicable.rb
|
44
|
-
|
45
|
-
homepage:
|
48
|
+
homepage: https://github.com/mushishi78/attire
|
46
49
|
licenses:
|
47
50
|
- MIT
|
48
51
|
metadata: {}
|
data/lib/attire/initializer.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'attire/core_ext/duplicable'
|
2
|
-
|
3
|
-
module Attire
|
4
|
-
class Initializer
|
5
|
-
def initialize(names, splat_name, block_name, after_initialize)
|
6
|
-
@names = names
|
7
|
-
@splat_name = splat_name
|
8
|
-
@block_name = block_name
|
9
|
-
@after_initialize = after_initialize
|
10
|
-
end
|
11
|
-
|
12
|
-
def instance_initialize(instance, values, value_block)
|
13
|
-
@instance, @values, @value_block = instance, values, value_block
|
14
|
-
arity_check
|
15
|
-
set_ivars
|
16
|
-
instance.instance_eval(&after_initialize) if after_initialize
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
attr_reader :names, :splat_name, :block_name, :after_initialize,
|
22
|
-
:instance, :values, :value_block
|
23
|
-
|
24
|
-
def set_ivars
|
25
|
-
names.zip(values).each do |name, value|
|
26
|
-
next set_hash(name, value) if name.is_a?(Hash)
|
27
|
-
next set_optional(name, value) if optional?(name)
|
28
|
-
set_ivar(name, value)
|
29
|
-
end
|
30
|
-
set_splat
|
31
|
-
set_block
|
32
|
-
end
|
33
|
-
|
34
|
-
def set_hash(defaults, values)
|
35
|
-
values ||= {}
|
36
|
-
hash_check(values)
|
37
|
-
defaults.each do |name, default|
|
38
|
-
next set_ivar(name, values[name]) unless values[name].nil?
|
39
|
-
set_ivar(name, default.duplicable? ? default.dup : default)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def set_optional(name, value)
|
44
|
-
name, default = name.to_s.split('=').map(&:strip)
|
45
|
-
value = instance.instance_eval(default) if value.nil?
|
46
|
-
set_ivar(name, value)
|
47
|
-
end
|
48
|
-
|
49
|
-
def set_splat
|
50
|
-
return unless splat_name
|
51
|
-
value_splat = values[names.length..values.length] || []
|
52
|
-
set_ivar(splat_name, value_splat)
|
53
|
-
end
|
54
|
-
|
55
|
-
def set_block
|
56
|
-
set_ivar(block_name, value_block) if block_name
|
57
|
-
end
|
58
|
-
|
59
|
-
def set_ivar(name, value)
|
60
|
-
instance.instance_variable_set("@#{name}", value)
|
61
|
-
end
|
62
|
-
|
63
|
-
def arity_check
|
64
|
-
return if arity_range.include?(values.length)
|
65
|
-
fail ArgumentError, "wrong number of arguments (#{values.length} for #{arity_range})"
|
66
|
-
end
|
67
|
-
|
68
|
-
def hash_check(value)
|
69
|
-
return if value.is_a?(Hash)
|
70
|
-
fail ArgumentError, "#{value} should be Hash."
|
71
|
-
end
|
72
|
-
|
73
|
-
def min_arity
|
74
|
-
last_required = names.reverse_each.find_index do |n|
|
75
|
-
!(optional?(n) || n.is_a?(Hash))
|
76
|
-
end
|
77
|
-
last_required ? names.length - last_required : 0
|
78
|
-
end
|
79
|
-
|
80
|
-
def max_arity
|
81
|
-
splat_name ? Float::INFINITY : names.length
|
82
|
-
end
|
83
|
-
|
84
|
-
def arity_range
|
85
|
-
@arity_range ||= (min_arity..max_arity)
|
86
|
-
end
|
87
|
-
|
88
|
-
def optional?(name)
|
89
|
-
name.to_s.include?('=')
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|