koine-attributes 0.1.4 → 0.2.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/.travis.yml +3 -0
- data/Rakefile +5 -6
- data/bin/console +3 -3
- data/koine-attributes.gemspec +2 -0
- data/lib/koine/attributes.rb +22 -19
- data/lib/koine/attributes/adapter/float.rb +0 -1
- data/lib/koine/attributes/attributes.rb +109 -6
- data/lib/koine/attributes/attributes_factory.rb +31 -0
- data/lib/koine/attributes/version.rb +1 -1
- metadata +32 -4
- data/lib/koine/attributes/builder.rb +0 -167
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: deb27fe7217e17e870a86be97914caa6b8d06694
|
4
|
+
data.tar.gz: 6b64a5897f5e12eb03d5e62551697733711df8b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38fec92fd56ebd54e19cccfc2ed7c640b20f4d453f23ef25fed90c8ed63b168ba43548fe98e7edf3d26dd6e6f262f8c1ba0bfda07a6b538631f7460d0397ed51
|
7
|
+
data.tar.gz: f0f593389f582857f67bec046cb7338a593282e9f2dee18e489c31cf63b5db9193af87d678252771c6f57a6c70a7759d009e4f2ae2eda432bd9ae3b53d467bd7
|
data/.travis.yml
CHANGED
data/Rakefile
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec)
|
5
5
|
|
6
|
-
task :
|
6
|
+
task default: :spec
|
7
7
|
|
8
8
|
namespace :test do
|
9
|
-
|
10
|
-
desc "run tests and generate invoke coveralls"
|
9
|
+
desc 'run tests and generate invoke coveralls'
|
11
10
|
task :coveralls do
|
12
11
|
ENV['COVERALLS'] = 'true'
|
13
12
|
Rake::Task['test:coverage'].invoke
|
14
13
|
end
|
15
14
|
|
16
|
-
desc
|
15
|
+
desc 'run tests and generate code coverage'
|
17
16
|
task :coverage do
|
18
17
|
ENV['COVERAGE'] = 'true'
|
19
18
|
Rake::Task[:spec].invoke
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'koine/attributes'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require "koine/attributes"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start(__FILE__)
|
data/koine-attributes.gemspec
CHANGED
@@ -36,4 +36,6 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
37
37
|
spec.add_development_dependency 'coveralls'
|
38
38
|
spec.add_development_dependency 'simplecov'
|
39
|
+
spec.add_development_dependency 'rubocop'
|
40
|
+
spec.add_development_dependency 'reek'
|
39
41
|
end
|
data/lib/koine/attributes.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'koine/attributes/version'
|
2
|
-
require 'koine/attributes/builder'
|
3
3
|
require 'koine/attributes/adapter/base'
|
4
4
|
|
5
5
|
# provides the following API
|
@@ -101,6 +101,7 @@ require 'koine/attributes/adapter/base'
|
|
101
101
|
module Koine
|
102
102
|
module Attributes
|
103
103
|
autoload :Attributes, 'koine/attributes/attributes'
|
104
|
+
autoload :AttributesFactory, 'koine/attributes/attributes_factory'
|
104
105
|
|
105
106
|
module Adapter
|
106
107
|
autoload :Boolean, 'koine/attributes/adapter/boolean'
|
@@ -114,42 +115,44 @@ module Koine
|
|
114
115
|
Error = Class.new(StandardError)
|
115
116
|
|
116
117
|
def self.included(base)
|
118
|
+
base.extend(Forwardable)
|
117
119
|
base.extend(ClassMethods)
|
118
120
|
end
|
119
121
|
|
120
122
|
module ClassMethods
|
121
123
|
def attributes(options = {}, &block)
|
122
|
-
@builder =
|
124
|
+
@builder = true
|
125
|
+
@_attributes_factory ||= AttributesFactory.new(options)
|
123
126
|
class_eval(&block)
|
124
127
|
|
125
|
-
|
126
|
-
|
128
|
+
instance_eval do
|
129
|
+
define_method :attributes do
|
130
|
+
@_attributes ||= self.class.instance_variable_get(:@_attributes_factory).create(self)
|
131
|
+
end
|
127
132
|
|
128
|
-
|
129
|
-
|
130
|
-
@builder.build_constructor(initializer_options)
|
131
|
-
else
|
132
|
-
@builder.build_lazy_attributes
|
133
|
+
define_method(:initialize) { |*args| attributes.initialize_values(*args) }
|
133
134
|
end
|
134
135
|
|
136
|
+
@_attributes_factory.freeze
|
137
|
+
|
135
138
|
@builder = nil
|
136
139
|
end
|
137
140
|
|
138
|
-
def attribute(name, adapter,
|
141
|
+
def attribute(name, adapter, lambda_arg = nil, &block)
|
139
142
|
unless @builder
|
140
143
|
raise Error, 'You must call .attribute inside the .attributes block'
|
141
144
|
end
|
142
145
|
|
143
|
-
|
144
|
-
|
145
|
-
end
|
146
|
+
block = lambda_arg || block
|
147
|
+
instance_variable_get(:@_attributes_factory).add_attribute(name, adapter, &block)
|
146
148
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
149
|
+
instance_eval do
|
150
|
+
def_delegators :attributes, name, "#{name}=", "with_#{name}"
|
151
|
+
|
152
|
+
define_method :== do |other|
|
153
|
+
attributes == other.attributes
|
154
|
+
end
|
155
|
+
end
|
153
156
|
end
|
154
157
|
end
|
155
158
|
end
|
@@ -1,17 +1,120 @@
|
|
1
1
|
module Koine
|
2
2
|
module Attributes
|
3
3
|
class Attributes
|
4
|
-
def initialize(object,
|
4
|
+
def initialize(object, adapters:, options: {})
|
5
5
|
@object = object
|
6
|
-
@
|
6
|
+
@adapters = adapters
|
7
|
+
@values = {}
|
8
|
+
@initializer = { strict: true, freeze: false, initialize: !options[:initializer].nil? }
|
9
|
+
|
10
|
+
if options[:initializer].is_a?(Hash)
|
11
|
+
@initializer = @initializer.merge(options[:initializer])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize_values(values = {})
|
16
|
+
if !@initializer[:initialize] && !values.empty?
|
17
|
+
raise ArgumentError, "wrong number of arguments (given #{values.length}, expected 0)"
|
18
|
+
end
|
19
|
+
|
20
|
+
return unless @initializer[:initialize]
|
21
|
+
set_values(values) && @initializer[:freeze] && freeze
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_values(values)
|
25
|
+
invalid_attributes = []
|
26
|
+
|
27
|
+
if @initializer[:strict]
|
28
|
+
attributes = values.keys.map(&:to_sym)
|
29
|
+
invalid_attributes = attributes - valid_attributes
|
30
|
+
end
|
31
|
+
|
32
|
+
unless invalid_attributes.empty?
|
33
|
+
raise ArgumentError, "Invalid attributes (#{invalid_attributes.join(', ')})"
|
34
|
+
end
|
35
|
+
|
36
|
+
values.each do |attribute, value|
|
37
|
+
set(attribute, value) if has_attribute?(attribute)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def set(attribute, value)
|
42
|
+
@values[attribute.to_sym] = adapter_for(attribute).coerce(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def with_attribute(attribute, value)
|
46
|
+
new_attributes = to_h.merge(attribute => value)
|
47
|
+
@object.class.new(new_attributes)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get(attribute)
|
51
|
+
@values[attribute.to_sym] || adapter_for(attribute).default_value
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(other)
|
55
|
+
other.to_h == to_h
|
7
56
|
end
|
8
57
|
|
9
58
|
def to_h
|
10
|
-
|
11
|
-
@
|
12
|
-
|
13
|
-
|
59
|
+
valid_attributes.map do |name|
|
60
|
+
[name.to_sym, @object.send(name)]
|
61
|
+
end.to_h
|
62
|
+
end
|
63
|
+
|
64
|
+
def respond_to?(method, _include_private = nil)
|
65
|
+
method = method.to_s
|
66
|
+
|
67
|
+
# getter
|
68
|
+
return true if has_attribute?(method)
|
69
|
+
|
70
|
+
# {attribute_name}=value
|
71
|
+
matches = method.match(/^(.*)=$/)
|
72
|
+
return has_attribute?(matches[1]) if matches
|
73
|
+
|
74
|
+
# with_{attribute}(value)
|
75
|
+
matches = method.match(/^with_(.*)$/)
|
76
|
+
return has_attribute?(matches[1]) if matches
|
77
|
+
|
78
|
+
false
|
79
|
+
end
|
80
|
+
|
81
|
+
def method_missing(method_name, *args)
|
82
|
+
unless respond_to?(method_name)
|
83
|
+
raise NoMethodError, "Undefined method #{method_name} for attributed object #{@object}"
|
84
|
+
end
|
85
|
+
|
86
|
+
method_name = method_name.to_s
|
87
|
+
|
88
|
+
if method_name.to_s =~ /=$/
|
89
|
+
attribute = method_name.to_s.delete('=')
|
90
|
+
return set(attribute, *args)
|
14
91
|
end
|
92
|
+
|
93
|
+
matches = method_name.match(/^with_(.*)$/)
|
94
|
+
return with_attribute(matches[1], *args) if matches
|
95
|
+
|
96
|
+
get(method_name)
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def valid_attributes
|
102
|
+
@adapters.keys
|
103
|
+
end
|
104
|
+
|
105
|
+
def has_attribute?(attribute)
|
106
|
+
@adapters.key?(attribute.to_sym)
|
107
|
+
end
|
108
|
+
|
109
|
+
def adapter_for(attribute)
|
110
|
+
@adapters.fetch(attribute.to_sym)
|
111
|
+
end
|
112
|
+
|
113
|
+
def freeze
|
114
|
+
@object.freeze
|
115
|
+
@adapters.freeze
|
116
|
+
@values.freeze
|
117
|
+
super
|
15
118
|
end
|
16
119
|
end
|
17
120
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Koine
|
2
|
+
module Attributes
|
3
|
+
class AttributesFactory
|
4
|
+
def initialize(options = {})
|
5
|
+
@adapters = {}
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def create(target_object)
|
10
|
+
Attributes.new(target_object, adapters: @adapters, options: @options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_attribute(name, adapter, &block)
|
14
|
+
adapter = coerce_adapter(adapter)
|
15
|
+
yield(adapter) if block
|
16
|
+
@adapters[name.to_sym] = adapter.freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
def coerce_adapter(adapter)
|
20
|
+
return adapter unless adapter.instance_of?(::Symbol)
|
21
|
+
Object.const_get("Koine::Attributes::Adapter::#{adapter.to_s.capitalize}").new
|
22
|
+
end
|
23
|
+
|
24
|
+
def freeze
|
25
|
+
super
|
26
|
+
@adapters.freeze
|
27
|
+
@options.freeze
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: koine-attributes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcelo Jacobus
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: reek
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
description: Stronger getter and setters for your ruby classes
|
84
112
|
email:
|
85
113
|
- marcelo.jacobus@xing.com
|
@@ -107,7 +135,7 @@ files:
|
|
107
135
|
- lib/koine/attributes/adapter/string.rb
|
108
136
|
- lib/koine/attributes/adapter/time.rb
|
109
137
|
- lib/koine/attributes/attributes.rb
|
110
|
-
- lib/koine/attributes/
|
138
|
+
- lib/koine/attributes/attributes_factory.rb
|
111
139
|
- lib/koine/attributes/hash_helper.rb
|
112
140
|
- lib/koine/attributes/version.rb
|
113
141
|
homepage: https://github.com/mjacobus/koine-attributes
|
@@ -131,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
159
|
version: '0'
|
132
160
|
requirements: []
|
133
161
|
rubyforge_project:
|
134
|
-
rubygems_version: 2.
|
162
|
+
rubygems_version: 2.6.13
|
135
163
|
signing_key:
|
136
164
|
specification_version: 4
|
137
165
|
summary: Stronger setters and getters
|
@@ -1,167 +0,0 @@
|
|
1
|
-
require 'koine/attributes/hash_helper'
|
2
|
-
|
3
|
-
module Koine
|
4
|
-
module Attributes
|
5
|
-
module Builder
|
6
|
-
class ClassBuilder
|
7
|
-
attr_reader :attributes
|
8
|
-
attr_reader :target
|
9
|
-
|
10
|
-
def initialize(target:)
|
11
|
-
@target = target
|
12
|
-
@attributes = []
|
13
|
-
@getter = GetterBuilder.new(attributes: attributes, target: target)
|
14
|
-
@setter = SetterBuilder.new(attributes: attributes, target: target)
|
15
|
-
@constructor = ConstructorBuilder.new(attributes: attributes, target: target)
|
16
|
-
@lazy_attributes = LazyAttributesBuilder.new(attributes: attributes, target: target)
|
17
|
-
end
|
18
|
-
|
19
|
-
def build(name, driver)
|
20
|
-
attributes.push(name.to_sym)
|
21
|
-
@getter.build(name, driver)
|
22
|
-
@setter.build(name, driver)
|
23
|
-
end
|
24
|
-
|
25
|
-
def build_constructor(strict: true, freeze: false)
|
26
|
-
@constructor.build(strict: strict, freeze: freeze)
|
27
|
-
end
|
28
|
-
|
29
|
-
def build_lazy_attributes
|
30
|
-
@lazy_attributes.build
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class BaseBuilder
|
35
|
-
attr_reader :attributes, :target
|
36
|
-
|
37
|
-
def initialize(attributes:, target:)
|
38
|
-
@attributes = attributes
|
39
|
-
@target = target
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
class GetterBuilder < BaseBuilder
|
44
|
-
def build(name, driver)
|
45
|
-
target.class_eval do
|
46
|
-
define_method(name) do
|
47
|
-
instance_variable_get("@#{name}") || driver.default_value
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class SetterBuilder < BaseBuilder
|
54
|
-
def build(name, driver)
|
55
|
-
setter = "#{name}="
|
56
|
-
|
57
|
-
target.class_eval do
|
58
|
-
define_method(setter) do |*args|
|
59
|
-
instance_variable_set("@#{name}", driver.coerce(*args))
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
class LazyAttributesBuilder < BaseBuilder
|
66
|
-
def build
|
67
|
-
valid_attributes = attributes
|
68
|
-
|
69
|
-
target.class_eval do
|
70
|
-
define_method :attributes do
|
71
|
-
@_koine_attributes ||= Koine::Attributes::Attributes.new(self, attributes: valid_attributes)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class ConstructorBuilder < BaseBuilder
|
78
|
-
def build(strict: true, freeze: false)
|
79
|
-
valid_attributes = attributes
|
80
|
-
|
81
|
-
target.class_eval do
|
82
|
-
define_method :initialize do |args = {}|
|
83
|
-
@_koine_attributes ||= Koine::Attributes::Attributes.new(self, attributes: valid_attributes)
|
84
|
-
initialize_attributes(args)
|
85
|
-
end
|
86
|
-
|
87
|
-
def attributes
|
88
|
-
@_koine_attributes
|
89
|
-
end
|
90
|
-
|
91
|
-
protected
|
92
|
-
|
93
|
-
define_method(:initialize_attributes) do |constructor_args|
|
94
|
-
invalid_attributes = []
|
95
|
-
constructor_args = HashHelper.new.symbolize_keys(constructor_args)
|
96
|
-
|
97
|
-
constructor_args.each do |name, value|
|
98
|
-
if valid_attributes.include?(name)
|
99
|
-
setter = "#{name}=".to_sym
|
100
|
-
send(setter, value)
|
101
|
-
next
|
102
|
-
end
|
103
|
-
|
104
|
-
next unless strict
|
105
|
-
invalid_attributes << name
|
106
|
-
end
|
107
|
-
|
108
|
-
unless invalid_attributes.empty?
|
109
|
-
attributes = invalid_attributes.join(', ')
|
110
|
-
raise ArgumentError, "Invalid attributes (#{attributes})"
|
111
|
-
end
|
112
|
-
|
113
|
-
self.freeze if freeze
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
if strict
|
118
|
-
make_setters_private
|
119
|
-
create_with_methods
|
120
|
-
create_comparator
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
protected
|
125
|
-
|
126
|
-
def make_setters_private
|
127
|
-
attrs = attributes
|
128
|
-
|
129
|
-
target.instance_eval do
|
130
|
-
attrs.each do |attr|
|
131
|
-
private "#{attr}="
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def create_with_methods
|
137
|
-
attributes.each do |attr|
|
138
|
-
create_with_method(attr)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def create_with_method(attr)
|
143
|
-
target.class_eval do
|
144
|
-
define_method "with_#{attr}" do |*args|
|
145
|
-
dup.tap do |new_object|
|
146
|
-
new_object.send("#{attr}=", *args)
|
147
|
-
new_object.freeze
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def create_comparator
|
154
|
-
attrs = attributes
|
155
|
-
|
156
|
-
target.class_eval do
|
157
|
-
define_method :== do |that|
|
158
|
-
a = attrs.map { |attr| send(attr) }
|
159
|
-
b = attrs.map { |attr| that.send(attr) }
|
160
|
-
a == b
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|