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 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.
@@ -23,5 +23,4 @@ Gem::Specification.new do |gem|
23
23
  gem.add_development_dependency 'coveralls'
24
24
  gem.add_development_dependency 'rake'
25
25
  gem.add_development_dependency 'bundler'
26
- gem.add_development_dependency "rake"
27
26
  end
@@ -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 = Array.wrap(attributes).flatten
31
+ attributes = Helpers.to_a(attributes).flatten
37
32
  return @@#{options[:as]} if attributes.empty?
38
33
 
39
- @@#{options[:as]}.slice(attributes.map { |attr| attr.to_sym })
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
@@ -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.symbolize_keys
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.extract_options!
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])
@@ -8,12 +8,4 @@ class Object
8
8
  def present?
9
9
  !blank?
10
10
  end unless method_defined? :present?
11
-
12
- def try(*a, &b)
13
- if a.empty? && block_given?
14
- yield self
15
- else
16
- __send__(*a, &b)
17
- end
18
- end unless method_defined? :try?
19
11
  end
@@ -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
@@ -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 Array.wrap(false_values).flatten.include?(value) ? false : true
11
+ return Helpers.to_a(false_values).flatten.include?(value) ? false : true
12
12
  else
13
- return Array.wrap(true_values).flatten.include?(value) ? true : false
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)
@@ -3,7 +3,7 @@
3
3
  module Attrio
4
4
  module Version
5
5
  MAJOR = 0
6
- MINOR = 2
6
+ MINOR = 3
7
7
  PATCH = 0
8
8
  BUILD = nil
9
9
 
@@ -1,59 +1,75 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Attrio do
4
- describe 'model' do
5
- let(:model) do
6
- Class.new { include Attrio }
7
- end
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
- it 'should respond_to define_attributes' do
10
- model.respond_to?(:define_attributes).should be_true
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 'without options' do
14
- let(:model) do
15
- Class.new do
16
- include Attrio
23
+ context 'instance' do
24
+ subject { model.new }
17
25
 
18
- define_attributes do
19
- end
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
- it 'should respond_to attributes' do
24
- model.respond_to?(:attributes).should be_true
25
- end
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
- describe 'object' do
28
- let(:object) { model.new }
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 respond_to reset_attributes' do
31
- object.respond_to?(:reset_attributes).should be_true
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
- context 'with option :as' do
37
- let(:model) do
38
- Class.new do
39
- include Attrio
55
+ context 'Attrio included with :as parameter' do
56
+ let(:attributes_name) do
57
+ 'api_attributes'
58
+ end
40
59
 
41
- define_attributes :as => :model_attributes do
42
- end
43
- end
44
- end
60
+ subject { model }
45
61
 
46
- it 'should respond_to model_attributes' do
47
- model.respond_to?(:model_attributes).should be_true
48
- end
62
+ it { should respond_to(:define_attributes) }
63
+ it { should respond_to(:api_attributes) }
49
64
 
50
- describe 'object' do
51
- let(:object) { model.new }
65
+ context 'instance' do
66
+ subject { model.new }
52
67
 
53
- it 'should respond_to reset_model_attributes' do
54
- object.respond_to?(:reset_model_attributes).should be_true
55
- end
56
- end
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.2.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-27 00:00:00.000000000 Z
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: 2070292704708193097
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: 2070292704708193097
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
@@ -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
@@ -1,7 +0,0 @@
1
- # encoding: utf-8
2
-
3
- class NilClass
4
- def try(*args)
5
- nil
6
- end
7
- end
@@ -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