attrio 0.2.0 → 0.3.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.
- data/README.md +10 -1
- data/attrio.gemspec +0 -1
- data/lib/attrio.rb +9 -13
- data/lib/attrio/attribute.rb +1 -1
- data/lib/attrio/attributes_parser.rb +1 -1
- data/lib/attrio/core_ext/object.rb +0 -8
- data/lib/attrio/helpers.rb +26 -0
- data/lib/attrio/types/boolean.rb +3 -3
- data/lib/attrio/version.rb +1 -1
- data/spec/attrio/attrio_spec.rb +54 -38
- metadata +5 -25
- data/lib/attrio/core_ext/array.rb +0 -23
- data/lib/attrio/core_ext/class.rb +0 -55
- data/lib/attrio/core_ext/hash.rb +0 -38
- data/lib/attrio/core_ext/nil_object.rb +0 -7
- data/lib/attrio/core_ext/time.rb +0 -17
data/README.md
CHANGED
@@ -37,7 +37,7 @@ class User
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
```
|
40
|
-
|
40
|
+
### Accessing attributes
|
41
41
|
By default Attrio defines `#attributes` accessor which contains `Hash` with attributes names as keys and instances of `Attrio::Attribute` as values. Each instance of `Attrio::Attribute` contains following information:
|
42
42
|
* type
|
43
43
|
* writer method name
|
@@ -55,6 +55,15 @@ user.attributes
|
|
55
55
|
# :age => #<Attrio::Attribute:0x007fc44e8d4c98 @object=#<User:0x007fc44e8b2b48>, @name="age", @type=Attrio::Types::Integer, @options={}, @writer_method_name="age=", @writer_visibility=:public, @instance_variable_name="@age", @reader_method_name="age", @reader_visibility=:public>,
|
56
56
|
# :birthday = >#<Attrio::Attribute:0x007fc44e8e2e38 @object=#<User:0x007fc44e8b2b48>, @name="birthday", @type=Attrio::Types::DateTime, @options={}, @writer_method_name="birthday=", @writer_visibility=:public, @instance_variable_name="@birthday", @reader_method_name="birthday", @reader_visibility=:public>
|
57
57
|
# }
|
58
|
+
user.attributes.keys
|
59
|
+
# => [:name, :age, :birthday]
|
60
|
+
```
|
61
|
+
|
62
|
+
Attributes can be filtered.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
user.attributes([:name, :age, :not_existing_attribute]).keys
|
66
|
+
# => [:name, :age]
|
58
67
|
```
|
59
68
|
|
60
69
|
Accessor name can be easily overridden by passing `:as` option to `define_attributes` block.
|
data/attrio.gemspec
CHANGED
data/lib/attrio.rb
CHANGED
@@ -2,21 +2,17 @@
|
|
2
2
|
|
3
3
|
require 'attrio/version'
|
4
4
|
|
5
|
-
require 'attrio/core_ext/array'
|
6
|
-
require 'attrio/core_ext/class'
|
7
|
-
require 'attrio/core_ext/hash'
|
8
|
-
require 'attrio/core_ext/nil_object'
|
9
5
|
require 'attrio/core_ext/object'
|
10
6
|
require 'attrio/core_ext/string'
|
11
|
-
require 'attrio/core_ext/time'
|
12
7
|
|
13
8
|
module Attrio
|
14
|
-
autoload :AttributesParser, 'attrio/attributes_parser'
|
9
|
+
autoload :AttributesParser, 'attrio/attributes_parser'
|
15
10
|
autoload :Initialize, 'attrio/initialize'
|
16
11
|
autoload :Inspect, 'attrio/inspect'
|
17
12
|
autoload :Reset, 'attrio/reset'
|
13
|
+
autoload :Helpers, 'attrio/helpers'
|
18
14
|
|
19
|
-
def self.included(base)
|
15
|
+
def self.included(base)
|
20
16
|
base.send :include, Attrio::Initialize
|
21
17
|
base.send :include, Attrio::Inspect
|
22
18
|
base.send :include, Attrio::Reset
|
@@ -27,16 +23,16 @@ module Attrio
|
|
27
23
|
module ClassMethods
|
28
24
|
def define_attributes(options = {}, &block)
|
29
25
|
options[:as] ||= :attributes
|
30
|
-
|
31
|
-
# cattr_accessor options[:as].to_sym
|
26
|
+
|
32
27
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
33
28
|
@@#{options[:as]} ||= {}
|
34
29
|
|
35
30
|
def self.#{options[:as]}(attributes = [])
|
36
|
-
attributes =
|
31
|
+
attributes = Helpers.to_a(attributes).flatten
|
37
32
|
return @@#{options[:as]} if attributes.empty?
|
38
33
|
|
39
|
-
@@#{options[:as]}.
|
34
|
+
attributes = @@#{options[:as]}.keys & attributes
|
35
|
+
@@#{options[:as]}.select{ |k,v| attributes.include?(k) }
|
40
36
|
end
|
41
37
|
|
42
38
|
def #{options[:as]}(attributes = [])
|
@@ -53,7 +49,7 @@ module Attrio
|
|
53
49
|
|
54
50
|
def const_missing(name)
|
55
51
|
Attrio::AttributesParser.cast_type(name) || super
|
56
|
-
end
|
52
|
+
end
|
57
53
|
end
|
58
54
|
|
59
55
|
autoload :Attribute, 'attrio/attribute'
|
@@ -74,4 +70,4 @@ module Attrio
|
|
74
70
|
autoload :Symbol, 'attrio/types/symbol'
|
75
71
|
autoload :Time, 'attrio/types/time'
|
76
72
|
end
|
77
|
-
end
|
73
|
+
end
|
data/lib/attrio/attribute.rb
CHANGED
@@ -5,7 +5,7 @@ module Attrio
|
|
5
5
|
attr_reader :klass, :name, :type, :options
|
6
6
|
|
7
7
|
def initialize(klass, name, type, options)
|
8
|
-
@klass = klass; @name = name; @type = type; @options = options
|
8
|
+
@klass = klass; @name = name; @type = type; @options = Helpers.symbolize_hash_keys(options)
|
9
9
|
end
|
10
10
|
|
11
11
|
def reader_method_name
|
@@ -14,7 +14,7 @@ module Attrio
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def attr(*args)
|
17
|
-
attribute_options = args.
|
17
|
+
attribute_options = (args.last.kind_of?(Hash) ? args.pop : Hash.new)
|
18
18
|
attribute_name = args[0].to_s
|
19
19
|
|
20
20
|
type = self.class.cast_type(attribute_options.delete(:type) || args[1])
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Attrio
|
2
|
+
module Helpers
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def to_a(object)
|
6
|
+
if object.nil?
|
7
|
+
[]
|
8
|
+
elsif object.respond_to?(:to_ary)
|
9
|
+
object.to_ary || [object]
|
10
|
+
else
|
11
|
+
[object]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# note that returning hash without symbolizing anything
|
16
|
+
# does not cause this to fail
|
17
|
+
def symbolize_hash_keys(hash)
|
18
|
+
hash.inject({}) do |new_hash, (key, value)|
|
19
|
+
new_hash[(key.to_sym rescue key) || key] = value
|
20
|
+
new_hash
|
21
|
+
end
|
22
|
+
hash
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/attrio/types/boolean.rb
CHANGED
@@ -8,10 +8,10 @@ module Attrio
|
|
8
8
|
false_values = options[:false] || options[:false_values]
|
9
9
|
|
10
10
|
if false_values.present?
|
11
|
-
return
|
11
|
+
return Helpers.to_a(false_values).flatten.include?(value) ? false : true
|
12
12
|
else
|
13
|
-
return
|
14
|
-
end
|
13
|
+
return Helpers.to_a(true_values).flatten.include?(value) ? true : false
|
14
|
+
end
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.typecasted?(value)
|
data/lib/attrio/version.rb
CHANGED
data/spec/attrio/attrio_spec.rb
CHANGED
@@ -1,59 +1,75 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Attrio do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
describe Attrio do
|
4
|
+
let(:model) do
|
5
|
+
attributes_name = self.respond_to?(:attributes_name) ? self.attributes_name : 'attributes'
|
6
|
+
Class.new do
|
7
|
+
include Attrio
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
define_attributes :as => attributes_name do
|
10
|
+
attr :name, String
|
11
|
+
attr :age, Integer
|
12
|
+
attr :created_at, DateTime, :default => proc{ Time.now }
|
13
|
+
end
|
11
14
|
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'Attrio included with default parameters' do
|
18
|
+
subject { model }
|
19
|
+
|
20
|
+
it { should respond_to(:define_attributes) }
|
21
|
+
it { should respond_to(:attributes) }
|
12
22
|
|
13
|
-
context '
|
14
|
-
|
15
|
-
Class.new do
|
16
|
-
include Attrio
|
23
|
+
context 'instance' do
|
24
|
+
subject { model.new }
|
17
25
|
|
18
|
-
|
19
|
-
|
26
|
+
it { should be }
|
27
|
+
it { should respond_to(:reset_attributes) }
|
28
|
+
it { should respond_to(:attributes) }
|
29
|
+
|
30
|
+
context '#attributes' do
|
31
|
+
it 'should be a kind of Hash' do
|
32
|
+
subject.attributes.should be_a_kind_of Hash
|
20
33
|
end
|
21
|
-
end
|
22
34
|
|
23
|
-
|
24
|
-
|
25
|
-
|
35
|
+
it 'should be present' do
|
36
|
+
subject.attributes.should be_present
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should return a full set of attributes' do
|
40
|
+
subject.attributes.keys.should match_array([:name, :age, :created_at])
|
41
|
+
end
|
26
42
|
|
27
|
-
|
28
|
-
|
43
|
+
it 'should return a filtered set of attributes' do
|
44
|
+
subject.attributes(:name).keys.should match_array([:name])
|
45
|
+
subject.attributes([:name]).keys.should match_array([:name])
|
46
|
+
end
|
29
47
|
|
30
|
-
it 'should
|
31
|
-
|
48
|
+
it 'should return a blank set of attributes for not existing filter' do
|
49
|
+
subject.attributes([:not_existing_attribute]).keys.should match_array([])
|
32
50
|
end
|
33
51
|
end
|
34
52
|
end
|
53
|
+
end
|
35
54
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
55
|
+
context 'Attrio included with :as parameter' do
|
56
|
+
let(:attributes_name) do
|
57
|
+
'api_attributes'
|
58
|
+
end
|
40
59
|
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
60
|
+
subject { model }
|
45
61
|
|
46
|
-
|
47
|
-
|
48
|
-
end
|
62
|
+
it { should respond_to(:define_attributes) }
|
63
|
+
it { should respond_to(:api_attributes) }
|
49
64
|
|
50
|
-
|
51
|
-
|
65
|
+
context 'instance' do
|
66
|
+
subject { model.new }
|
52
67
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
68
|
+
it { should be }
|
69
|
+
it { should respond_to(:reset_api_attributes) }
|
70
|
+
it { should respond_to(:api_attributes) }
|
71
|
+
|
72
|
+
its(:api_attributes){ should be_present }
|
57
73
|
end
|
58
74
|
end
|
59
75
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attrio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-05
|
13
|
+
date: 2013-06-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -108,22 +108,6 @@ dependencies:
|
|
108
108
|
- - ! '>='
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rake
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
none: false
|
115
|
-
requirements:
|
116
|
-
- - ! '>='
|
117
|
-
- !ruby/object:Gem::Version
|
118
|
-
version: '0'
|
119
|
-
type: :development
|
120
|
-
prerelease: false
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
122
|
-
none: false
|
123
|
-
requirements:
|
124
|
-
- - ! '>='
|
125
|
-
- !ruby/object:Gem::Version
|
126
|
-
version: '0'
|
127
111
|
description:
|
128
112
|
email: hello@jetrockets.ru
|
129
113
|
executables: []
|
@@ -144,18 +128,14 @@ files:
|
|
144
128
|
- lib/attrio/builders/accessor_builder.rb
|
145
129
|
- lib/attrio/builders/reader_builder.rb
|
146
130
|
- lib/attrio/builders/writer_builder.rb
|
147
|
-
- lib/attrio/core_ext/array.rb
|
148
|
-
- lib/attrio/core_ext/class.rb
|
149
|
-
- lib/attrio/core_ext/hash.rb
|
150
|
-
- lib/attrio/core_ext/nil_object.rb
|
151
131
|
- lib/attrio/core_ext/object.rb
|
152
132
|
- lib/attrio/core_ext/string.rb
|
153
|
-
- lib/attrio/core_ext/time.rb
|
154
133
|
- lib/attrio/default_value.rb
|
155
134
|
- lib/attrio/default_value/base.rb
|
156
135
|
- lib/attrio/default_value/callable.rb
|
157
136
|
- lib/attrio/default_value/clonable.rb
|
158
137
|
- lib/attrio/default_value/symbol.rb
|
138
|
+
- lib/attrio/helpers.rb
|
159
139
|
- lib/attrio/initialize.rb
|
160
140
|
- lib/attrio/inspect.rb
|
161
141
|
- lib/attrio/reset.rb
|
@@ -200,7 +180,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
200
180
|
version: '0'
|
201
181
|
segments:
|
202
182
|
- 0
|
203
|
-
hash:
|
183
|
+
hash: -2263639350992331288
|
204
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
185
|
none: false
|
206
186
|
requirements:
|
@@ -209,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
189
|
version: '0'
|
210
190
|
segments:
|
211
191
|
- 0
|
212
|
-
hash:
|
192
|
+
hash: -2263639350992331288
|
213
193
|
requirements: []
|
214
194
|
rubyforge_project:
|
215
195
|
rubygems_version: 1.8.24
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
class Array # :nodoc:
|
4
|
-
def extract_options!
|
5
|
-
if last.is_a?(Hash) && last.extractable_options?
|
6
|
-
pop
|
7
|
-
else
|
8
|
-
{}
|
9
|
-
end
|
10
|
-
end unless method_defined?(:extract_options!)
|
11
|
-
|
12
|
-
class << self
|
13
|
-
def wrap(object)
|
14
|
-
if object.nil?
|
15
|
-
[]
|
16
|
-
elsif object.respond_to?(:to_ary)
|
17
|
-
object.to_ary || [object]
|
18
|
-
else
|
19
|
-
[object]
|
20
|
-
end
|
21
|
-
end unless method_defined?(:wrap)
|
22
|
-
end
|
23
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
class Class
|
4
|
-
def cattr_reader(*syms)
|
5
|
-
options = syms.extract_options!
|
6
|
-
syms.each do |sym|
|
7
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
8
|
-
unless defined? @@#{sym}
|
9
|
-
@@#{sym} = nil
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.#{sym}
|
13
|
-
@@#{sym}
|
14
|
-
end
|
15
|
-
EOS
|
16
|
-
|
17
|
-
unless options[:instance_reader] == false || options[:instance_accessor] == false
|
18
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
19
|
-
def #{sym}
|
20
|
-
@@#{sym}
|
21
|
-
end
|
22
|
-
EOS
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end unless method_defined?(:cattr_reader)
|
26
|
-
|
27
|
-
def cattr_writer(*syms)
|
28
|
-
options = syms.extract_options!
|
29
|
-
syms.each do |sym|
|
30
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
31
|
-
unless defined? @@#{sym}
|
32
|
-
@@#{sym} = nil
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.#{sym}=(obj)
|
36
|
-
@@#{sym} = obj
|
37
|
-
end
|
38
|
-
EOS
|
39
|
-
|
40
|
-
unless options[:instance_writer] == false || options[:instance_accessor] == false
|
41
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
42
|
-
def #{sym}=(obj)
|
43
|
-
@@#{sym} = obj
|
44
|
-
end
|
45
|
-
EOS
|
46
|
-
end
|
47
|
-
self.send("#{sym}=", yield) if block_given?
|
48
|
-
end
|
49
|
-
end unless method_defined?(:cattr_writer)
|
50
|
-
|
51
|
-
def cattr_accessor(*syms, &blk)
|
52
|
-
cattr_reader(*syms)
|
53
|
-
cattr_writer(*syms, &blk)
|
54
|
-
end unless method_defined?(:cattr_accessor)
|
55
|
-
end
|
data/lib/attrio/core_ext/hash.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
class Hash # :nodoc:
|
4
|
-
def symbolize_keys # :nodoc:
|
5
|
-
inject({}) do |hash, (key, value)|
|
6
|
-
hash[(key.to_sym rescue key) || key] = value
|
7
|
-
hash
|
8
|
-
end
|
9
|
-
end unless method_defined?(:symbolize_keys)
|
10
|
-
|
11
|
-
def symbolize_keys! # :nodoc:
|
12
|
-
hash = symbolize_keys
|
13
|
-
hash.each do |key, val|
|
14
|
-
hash[key] = case val
|
15
|
-
when Hash
|
16
|
-
val.symbolize_keys!
|
17
|
-
when Array
|
18
|
-
val.map do |item|
|
19
|
-
item.is_a?(Hash) ? item.symbolize_keys! : item
|
20
|
-
end
|
21
|
-
else
|
22
|
-
val
|
23
|
-
end
|
24
|
-
end
|
25
|
-
return hash
|
26
|
-
end unless method_defined?(:symbolize_keys!)
|
27
|
-
|
28
|
-
def extractable_options?
|
29
|
-
instance_of?(Hash)
|
30
|
-
end unless method_defined?(:extractable_options?)
|
31
|
-
|
32
|
-
def slice(*keys)
|
33
|
-
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
|
34
|
-
hash = self.class.new
|
35
|
-
keys.each { |k| hash[k] = self[k] if has_key?(k) }
|
36
|
-
hash
|
37
|
-
end unless method_defined?(:slice?)
|
38
|
-
end # Hash
|
data/lib/attrio/core_ext/time.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
class Time # :nodoc:
|
4
|
-
class << self
|
5
|
-
def strptime(date, format, now=self.now)
|
6
|
-
d = Date._strptime(date, format)
|
7
|
-
raise ArgumentError, "invalid strptime format - `#{format}'" unless d
|
8
|
-
if seconds = d[:seconds]
|
9
|
-
Time.at(seconds)
|
10
|
-
else
|
11
|
-
year = d[:year]
|
12
|
-
year = yield(year) if year && block_given?
|
13
|
-
make_time(year, d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now)
|
14
|
-
end
|
15
|
-
end unless method_defined?(:strptime)
|
16
|
-
end
|
17
|
-
end
|