kwattr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 178bc67e1d1f7cdc032e4e1b55349992fb00869e
4
+ data.tar.gz: fd9698a022ccb2c69b6f63f239bc67dc4169b9cf
5
+ SHA512:
6
+ metadata.gz: 52e4ef1bb5e95c1a9f5a3477cf3fc279cc4f53939c8e4204bd141a4bcb4294b1b017d06bc6b4db2e04a4b2f33fd6c91b4d53e61cf4d3c9d4da2bb8ec0f77a00e
7
+ data.tar.gz: c0f7229e9e29e9bf9ae82831cb6b3ce2300684fec79c9c0c2f43b4bbe9fe6d6e6396b1624cfbf23c22e7bbebee0268c148cd9797f8d768051b11f0201f4b02bc
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kwattr.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # KWattr
2
+
3
+ Keyword arguments meet attribute definitions and initialize:
4
+
5
+ ```ruby
6
+ class FooBar
7
+ kwattr :foo, :bar
8
+ end
9
+
10
+ FooBar.new foo: 42, bar: 21
11
+ # => #<FooBar @foo=42, @bar=21>
12
+ ```
13
+
14
+ instead of
15
+
16
+ ```ruby
17
+ class FooBar
18
+ attr_reader :foo, :bar
19
+
20
+ def initialize(foo:, bar:)
21
+ @foo = foo
22
+ @bar = bar
23
+ end
24
+ end
25
+ ```
26
+
27
+ ### Default values
28
+
29
+ ```ruby
30
+ class Foo
31
+ kwattr foo: 42
32
+ end
33
+
34
+ Foo.new
35
+ # => #<Foo @foo=42>
36
+ ```
37
+
38
+ ### Overriding initialize
39
+
40
+ The default initialize is prepended so there's no need to call `super` in
41
+ initialize, and attributes are already set.
42
+
43
+ ```ruby
44
+ $over = []
45
+
46
+ class Over
47
+ kwattr foo: 42
48
+
49
+ def initialize
50
+ $over << foo
51
+ end
52
+ end
53
+
54
+ Over.new
55
+ Over.new foo: 21
56
+ $over
57
+ # => [42, 21]
58
+ ```
59
+
60
+ ### Subclass
61
+
62
+ ```ruby
63
+ class Bar < Foo
64
+ kwattr :bar
65
+ end
66
+
67
+ Bar.new bar: 42
68
+ # => #<Bar @foo=42, @bar=42>
69
+ ```
70
+
71
+ ### Include
72
+
73
+ ```ruby
74
+ module Mod
75
+ kwattr :mod
76
+ end
77
+
78
+ class Inc
79
+ include Mod
80
+ end
81
+
82
+ Inc.new mod: 42
83
+ ```
84
+
85
+ ## Installation
86
+
87
+ Add this line to your application's Gemfile:
88
+
89
+ ```ruby
90
+ gem 'kwattr'
91
+ ```
92
+
93
+ And then execute:
94
+
95
+ $ bundle
96
+
97
+ Or install it yourself as:
98
+
99
+ $ gem install kwattr
100
+
101
+ ## Development
102
+
103
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
104
+ `bin/console` for an interactive prompt that will allow you to experiment.
105
+
106
+ ## Contributing
107
+
108
+ 1. Fork it ( https://github.com/etiennebarrie/kwattr/fork )
109
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
110
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
111
+ 4. Push to the branch (`git push origin my-new-feature`)
112
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default do
4
+ ruby "test.rb"
5
+ end
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kwattr"
5
+
6
+ require "irb"
7
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
data/kwattr.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kwattr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kwattr"
8
+ spec.version = KWattr::VERSION
9
+ spec.authors = ["Étienne Barrié"]
10
+ spec.email = ["etienne.barrie@gmail.com"]
11
+
12
+ spec.summary = %q{attr_reader + initialize with keyword arguments}
13
+ spec.description = %q{}
14
+ spec.homepage = "https://github.com/etiennebarrie/kwattr"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.9"
20
+ spec.add_development_dependency "rake", "~> 10.0"
21
+ end
@@ -0,0 +1,3 @@
1
+ module KWattr
2
+ VERSION = "0.1.0"
3
+ end
data/lib/kwattr.rb ADDED
@@ -0,0 +1,55 @@
1
+ require "kwattr/version"
2
+
3
+ module KWAttr
4
+
5
+ def kwattr(*attrs, **opts)
6
+ attr_reader(*attrs, *opts.keys)
7
+ prepend Initializer
8
+ extend Heritable
9
+ required, defaults = kwattrs
10
+ attrs.each { |attr| required << attr unless required.include?(attr) }
11
+ defaults.merge!(opts)
12
+ end
13
+
14
+ def kwattrs
15
+ @kwattrs ||= [[], {}]
16
+ end
17
+
18
+ module Heritable
19
+ def inherited(subclass)
20
+ required, defaults = kwattrs
21
+ subclass.kwattr(*required, **defaults)
22
+ end
23
+
24
+ alias_method :included, :inherited
25
+ end
26
+
27
+ module Initializer
28
+ def initialize(*args, **kwargs)
29
+ required, defaults = self.class.kwattrs
30
+ required = required.dup
31
+ defaults.merge(kwargs).each_pair do |key, value|
32
+ next unless required.delete(key) || defaults.key?(key)
33
+ kwargs.delete(key)
34
+ instance_variable_set "@#{key}", value
35
+ end
36
+ unless required.empty?
37
+ raise ArgumentError,
38
+ "missing keyword#{'s' if required.size > 1}: #{required.join(', ')}"
39
+ end
40
+ if method(:initialize).super_method.arity == args.size && !kwargs.empty?
41
+ raise ArgumentError,
42
+ "unknown keyword#{'s' if kwargs.size > 1}: #{kwargs.keys.join(', ')}"
43
+ end
44
+ args << kwargs unless kwargs.empty?
45
+ super(*args)
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ public def kwattr(*args)
52
+ raise TypeError, "wrong type #{self.class} (expected Module)" unless Module === self
53
+ extend KWAttr
54
+ kwattr(*args)
55
+ end
data/test.rb ADDED
@@ -0,0 +1,200 @@
1
+ require 'kwattr'
2
+
3
+ class Test
4
+ kwattr :foo, :bar
5
+ end
6
+
7
+ test = Test.new(foo: 42, bar: 21)
8
+ fail unless p(test.foo) == 42
9
+ fail unless p(test.bar) == 21
10
+
11
+ def raises?(exception_class)
12
+ yield
13
+ return
14
+ rescue exception_class
15
+ return p $!
16
+ end
17
+
18
+ fail unless raises?(TypeError) { kwattr }
19
+
20
+ fail unless raises?(ArgumentError) { Test.new }
21
+ fail unless raises?(ArgumentError) { Test.new(foo: 42) }
22
+ fail unless raises?(ArgumentError) { Test.new(foo: 42, bar: 21, baz: 43) }
23
+
24
+ class Test2
25
+ kwattr :titi
26
+ kwattr :toto
27
+ end
28
+
29
+ test = Test2.new(titi: 1, toto: 2)
30
+ fail unless p(test.titi) == 1
31
+ fail unless p(test.toto) == 2
32
+
33
+ class TestDescendant < Test
34
+ kwattr :bar
35
+ kwattr :baz
36
+ end
37
+
38
+ test = TestDescendant.new(foo: 42, bar: 21, baz: 14)
39
+ fail unless p(test.foo) == 42
40
+ fail unless p(test.bar) == 21
41
+ fail unless p(test.baz) == 14
42
+
43
+ class TestInitialize
44
+ kwattr :foo, :bar
45
+ attr :baz
46
+
47
+ def initialize(baz: 42)
48
+ @baz = baz / 3
49
+ end
50
+ end
51
+
52
+ test = TestInitialize.new(foo: 42, bar: 21)
53
+ fail unless p(test.foo) == 42
54
+ fail unless p(test.bar) == 21
55
+ fail unless p(test.baz) == 14
56
+ test = TestInitialize.new(foo: 42, bar: 21, baz: 21)
57
+ fail unless p(test.baz) == 7
58
+
59
+ class TestPositional
60
+ kwattr :foo, :bar
61
+ attr :x, :y
62
+
63
+ def initialize(x, y)
64
+ @x = x
65
+ @y = y
66
+ end
67
+ end
68
+
69
+ test = TestPositional.new(1, 2, foo: 42, bar: 21)
70
+ fail unless p(test.x) == 1
71
+ fail unless p(test.y) == 2
72
+ fail unless p(test.foo) == 42
73
+ fail unless p(test.bar) == 21
74
+
75
+ class TestOptionalKeyword
76
+ kwattr foo: 42
77
+ kwattr :bar
78
+ end
79
+
80
+ test = TestOptionalKeyword.new(bar: 21)
81
+ fail unless p(test.foo) == 42
82
+ fail unless p(test.bar) == 21
83
+ test = TestOptionalKeyword.new(foo: 21, bar: 42)
84
+ fail unless p(test.foo) == 21
85
+
86
+ class TestPositionalDescendant < TestPositional
87
+ kwattr baz: 14
88
+ end
89
+
90
+ test = TestPositionalDescendant.new(1, 2, foo: 42, bar: 21)
91
+ fail unless p(test.x) == 1
92
+ fail unless p(test.y) == 2
93
+ fail unless p(test.foo) == 42
94
+ fail unless p(test.bar) == 21
95
+ fail unless p(test.baz) == 14
96
+
97
+ class TestPositionalDescendantMore < TestPositionalDescendant
98
+ attr :z
99
+
100
+ def initialize(x, y, z, **options)
101
+ super(x, y, **options)
102
+ @z = z
103
+ end
104
+ end
105
+
106
+ test = TestPositionalDescendantMore.new(1, 2, 3, foo: 42, bar: 21)
107
+ fail unless p(test.x) == 1
108
+ fail unless p(test.y) == 2
109
+ fail unless p(test.z) == 3
110
+ fail unless p(test.foo) == 42
111
+ fail unless p(test.bar) == 21
112
+ fail unless p(test.baz) == 14
113
+
114
+ class TestPositionalDescendantFull < TestPositionalDescendant
115
+ attr :z
116
+ kwattr opt: 42
117
+ kwattr :req
118
+
119
+ def initialize(x, y, z, **options)
120
+ super(x, y, **options)
121
+ @z = z
122
+ end
123
+ end
124
+
125
+ test = TestPositionalDescendantFull.new(1, 2, 3, foo: 42, bar: 21, opt: 7, req: 6)
126
+ fail unless p(test.x) == 1
127
+ fail unless p(test.y) == 2
128
+ fail unless p(test.z) == 3
129
+ fail unless p(test.foo) == 42
130
+ fail unless p(test.bar) == 21
131
+ fail unless p(test.baz) == 14
132
+ fail unless p(test.opt) == 7
133
+ fail unless p(test.req) == 6
134
+
135
+ class TestDefaults
136
+ kwattr foo: 42, bar: 21
137
+ end
138
+
139
+ test = TestDefaults.new
140
+ fail unless p(test.foo) == 42
141
+ fail unless p(test.bar) == 21
142
+
143
+ class TestKeywordArgs
144
+ kwattr foo: 42
145
+ attr :bar
146
+
147
+ def initialize(bar: 21)
148
+ @bar = bar * 3
149
+ end
150
+ end
151
+
152
+ test = TestKeywordArgs.new(foo: 42, bar: 14)
153
+ fail unless p(test.foo) == 42
154
+ fail unless p(test.bar) == 42
155
+
156
+ class TestInit
157
+ kwattr foo: 42, bar: 21
158
+
159
+ def initialize
160
+ @inits ||= []
161
+ @inits << 1
162
+ end
163
+ end
164
+
165
+ class TestInitDescendant < TestInit
166
+ kwattr baz: 14
167
+ attr :inits
168
+
169
+ def initialize(*)
170
+ super
171
+ @inits << 2
172
+ end
173
+ end
174
+
175
+ test = TestInit.new(bar: 42)
176
+ test = TestInitDescendant.new(baz: 7)
177
+ fail unless p(test.inits) == [1, 2]
178
+
179
+ module Foo
180
+ kwattr :foo
181
+ end
182
+
183
+ class TestModule
184
+ include Foo
185
+ end
186
+
187
+ test = TestModule.new(foo: 42)
188
+ fail unless p(test.foo) == 42
189
+
190
+ module Bar
191
+ kwattr :bar
192
+ end
193
+
194
+ class TestModules
195
+ include Foo, Bar
196
+ end
197
+
198
+ test = TestModules.new(foo: 42, bar: 21)
199
+ fail unless p(test.foo) == 42
200
+ fail unless p(test.bar) == 21
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kwattr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - "Étienne Barrié"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: ''
42
+ email:
43
+ - etienne.barrie@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".travis.yml"
50
+ - CODE_OF_CONDUCT.md
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - bin/console
55
+ - bin/setup
56
+ - kwattr.gemspec
57
+ - lib/kwattr.rb
58
+ - lib/kwattr/version.rb
59
+ - test.rb
60
+ homepage: https://github.com/etiennebarrie/kwattr
61
+ licenses: []
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.4.5
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: attr_reader + initialize with keyword arguments
83
+ test_files: []