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 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