attire 1.1.0 → 2.0.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: a422961944b405505f20ccd99b7cf098378f18bf
4
- data.tar.gz: 84b4261dca389bb26a7b52ad9f0981c2425dfafd
3
+ metadata.gz: e47510ce77fba871c171411ee89810f79bbe8231
4
+ data.tar.gz: 1ed7fbacff39b565ce85235d25e376941006021f
5
5
  SHA512:
6
- metadata.gz: 22c26d505363455eafd750f6c385201d1eab0133f9b178f3b98c79fe31d504f8b2aa23d5aff4ceb512c8e3f8ba3596670dc6a3f2f4b6f4aa658a9a21cd0e5edc
7
- data.tar.gz: 10ab969e34aff9b34188334d70d1dd8976fcb25ed5ea7e21aa0a437f139b0a70826dcdb14333b99046314c2afd60c456a0a16b0f16ba01abc8eb555ff9fff9e8
6
+ metadata.gz: 08e1829aecf20e6405dbcc3f2189a097f13cf8368de2770095857fd6968d02491106f0c52fba094b9d6c5a8cd50f8f4f885c11d1391440f8acd92fa5c2590d5c
7
+ data.tar.gz: 1c7084866f5e17483c32ed4fa9a20810d57b1aa5904909dd2e2712e369d85a9821e6addbc3b6dea03717c58c4e8d6215ca6d39e0a589ed6b17b1cc471a0a1203
data/README.md CHANGED
@@ -3,87 +3,53 @@
3
3
  [![Build Status](https://travis-ci.org/mushishi78/attire.svg?branch=master)](https://travis-ci.org/mushishi78/attire)
4
4
  [![Gem Version](https://badge.fury.io/rb/attire.svg)](http://badge.fury.io/rb/attire)
5
5
 
6
- Convenience methods to remove some boiler plate in defining classes. Inspired by [attr_extras](https://github.com/barsoom/attr_extras).
6
+ Mixins to remove some boiler plate in defining classes.
7
7
 
8
- ## attr_init
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
- ``` ruby
11
- attr_init :foo, :bar, fizz: 15, pop: nil
12
- ```
10
+ ## Initializer
13
11
 
14
- Defines the following:
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
- def initialize(foo, bar, opts = {})
18
- @foo = foo
19
- @bar = bar
20
- @fizz = opts[:fizz]
21
- @pop = opts[:pop]
22
- end
15
+ require 'attire'
23
16
 
24
- private
17
+ class MyClass
18
+ extend Attire::Initializer
25
19
 
26
- attr_reader :foo, :bar, :pop
20
+ def initialize(foo:, bar: 24)
21
+ @bar = bar * 2
22
+ end
27
23
 
28
- def fizz
29
- @fizz ||= 15
24
+ def result
25
+ foo + bar
26
+ end
30
27
  end
31
- ```
32
28
 
33
- Optional, splat and blocks arguments can also be defined:
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
- 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
- ```
33
+ ## MethodObject
52
34
 
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:
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
- attr_method :spread, :cheese, crackers_class: Jacobs
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
- Require library:
61
+ ## Inspirations
96
62
 
97
- ``` ruby
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/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
- 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: 1.1.0
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-03-03 00:00:00.000000000 Z
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/attr_init.rb
43
- - lib/attire/attr_init/arguments.rb
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: Convenience methods to remove some boiler plate in defining classes.
67
+ summary: Mixins to remove some boiler plate in defining classes.
72
68
  test_files: []
@@ -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