moosex 0.0.5 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4148ee310961686e2246bd4ce922984b2d5890f4
4
- data.tar.gz: 5cd59e49ecd649fa8eec2e14949aa91b7ac53e78
3
+ metadata.gz: 8494a9819b7d500cafd3b8296714bd59cbcdad27
4
+ data.tar.gz: 2939d832b895dd24a00a829030de65f315cb6005
5
5
  SHA512:
6
- metadata.gz: fccc982b45dbf7bc095acb933df761ddacdddd202fe4afbda18e361e55d576209772aa734a01906e8acf37a83dff2ee8ba71a4f7528bf955c0986cce54f23839
7
- data.tar.gz: ef15d0179cf5f72b49b7f0978162f8780f2dc5b3c4a6a346e0d4dcfbe56bbe3f32d9a5aa06148c77db1414ffcef397bb4a2f2b1d30301482608afb7c0b1bc893
6
+ metadata.gz: 2510660f1124aedb3221696c4b20f4e45aaa3cf2c6ae42f2457c19d918ef45fb7e6d9afedca3b37e71d3cd3c1997e79f83f5064d4bb050a2b6943c647a8859e9
7
+ data.tar.gz: d0551a59229e8bbb1bffabbfe72443d0d2e2993e3ceae24d99afdb7adbd8ee616f01ef39ef3c703eca04b07681b8e4e79caf0e70178b6e462b87eaa0a5fd3758
data/.travis.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.2-p320
3
+ - 2.0.0
4
4
  - 2.1.0
data/Changelog CHANGED
@@ -1,3 +1,11 @@
1
+ 0.0.7 - 2014-02-01
2
+ - add min version of ruby should be 2.0.x
3
+
4
+ 0.0.6 - 2014-02-01
5
+ - fix bug when extends subclass, now it is safe #18
6
+ - required attr with default value will no longer throw exception #30
7
+ - supports handles for: single method, array, Class or Module #27
8
+
1
9
  0.0.5 - 2014-01-31
2
10
  - should support handles #13 (partial)
3
11
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- moosex (0.0.5)
4
+ moosex (0.0.7)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -13,9 +13,9 @@ GEM
13
13
  rspec-expectations (~> 2.14.0)
14
14
  rspec-mocks (~> 2.14.0)
15
15
  rspec-core (2.14.7)
16
- rspec-expectations (2.14.4)
16
+ rspec-expectations (2.14.5)
17
17
  diff-lcs (>= 1.1.3, < 2.0)
18
- rspec-mocks (2.14.4)
18
+ rspec-mocks (2.14.5)
19
19
 
20
20
  PLATFORMS
21
21
  ruby
data/README.md CHANGED
@@ -2,96 +2,107 @@
2
2
 
3
3
  A postmodern object system for Ruby [![Build Status](https://travis-ci.org/peczenyj/MooseX.png)](https://travis-ci.org/peczenyj/MooseX)
4
4
 
5
- ```ruby
6
- require 'moosex'
7
-
8
- class Point
9
- include MooseX
10
-
11
- has :x , {
12
- :is => :rw, # read-write
13
- :isa => Integer, # should be Integer
14
- :default => 0, # default value is 0 (constant)
15
- }
16
-
17
- has :y , {
18
- :is => :rw,
19
- :isa => Integer,
20
- :default => lambda { 0 }, # you should specify a lambda
21
- }
22
-
23
- def clear
24
- self.x= 0 # to run with type-check you must
25
- self.y= 0 # use the setter instad @x=
26
- end
27
- end
28
-
29
- class Foo
30
- include MooseX
31
-
32
- has :bar, {
33
- :is => :rwp, # read-write-private (private setter)
34
- :isa => Integer,
35
- :required => true, # you should require in the constructor
36
- }
37
- end
38
-
39
- class Baz
40
- include MooseX
41
-
42
- has :bam, {
43
- :is => :ro, # read-only, you should specify in new only
44
- :isa => lambda {|x| # you should add your own validator
45
- raise 'x should be less than 100' if x > 100
46
- },
47
- :required => true,
48
- :predicate => true, # add has_bam? method, ask if the attribute is unset
49
- :clearer => true, # add reset_bam! method, unset the attribute
50
- }
51
-
52
- end
53
-
54
- class Lol
55
- include MooseX
56
-
57
- has [:a, :b], { # define attributes a and b
58
- :is => :ro, # with same set of properties
59
- :default => 0,
60
- }
61
-
62
- has :c => { # alternative syntax to be
63
- :is => :ro, # more similar to Moo/Moose
64
- :default => 1,
65
- :predicate => :can_haz_c?, # custom predicate
66
- :clearer => "desintegrate_c", # force coerce to symbol
67
- }
68
- end
69
-
70
- class Target
71
- def method_x
72
- 1024
73
- end
74
- end
5
+ THIS MODULE IS EXPERIMENTAL YET! BE CAREFUL!
75
6
 
76
- class Proxy
77
- include MooseX
7
+ Talk is cheap. Show me the code!
78
8
 
79
- has :target, {
80
- :is => :ro,
81
- :default => lambda { Target.new() },
82
- :handles => {
83
- :my_method_x => :method_x,# create my_method_x in Proxy
84
- }, # this will delegate to @target.method_x
85
- }
86
- end
87
-
88
- # now you have a generic constructor
89
- p1 = Point.new # x and y will be 0
90
- p2 = Point.new( :x => 5 ) # y will be 0
91
- p3 = Point.new( :x => 5, :y => 4)
92
- foo = Foo.new( :bar => 123 ) # without bar will raise exception
93
- baz = Baz.new( :bam => 99 ) # if bam > 100 will raise exception
94
- Proxy.new.my_method_x # will call method_x in target, return 1024
9
+ ```ruby
10
+ require 'moosex'
11
+
12
+ class Point
13
+ include MooseX
14
+
15
+ has x: {
16
+ is: :rw, # read-write (mandatory)
17
+ isa: Integer, # should be Integer
18
+ default: 0, # default value is 0 (constant)
19
+ }
20
+
21
+ has y: {
22
+ is: :rw,
23
+ isa: Integer,
24
+ default: lambda { 0 }, # you should specify a lambda
25
+ }
26
+
27
+ def clear
28
+ self.x= 0 # to run with type-check you must
29
+ self.y= 0 # use the setter instad @x=
30
+ end
31
+ end
32
+
33
+ class Foo
34
+ include MooseX
35
+
36
+ has bar: {
37
+ is: :rwp, # read-write-private (private setter)
38
+ required: true, # you should require in the constructor
39
+ }
40
+ end
41
+
42
+ class Baz
43
+ include MooseX
44
+
45
+ has bam: {
46
+ is: :ro, # read-only, you should specify in new only
47
+ isa: lambda do |bam| # you should add your own validator
48
+ raise 'bam should be less than 100' if bam > 100
49
+ end,
50
+ required: true,
51
+ }
52
+
53
+ has boom: {
54
+ is: :rw,
55
+ predicate: true, # add has_boom? method, ask if the attribute is unset
56
+ clearer: true, # add reset_boom! method, unset the attribute
57
+ }
58
+ end
59
+
60
+ class Lol
61
+ include MooseX
62
+
63
+ has [:a, :b], { # define attributes a and b
64
+ is: :ro, # with same set of properties
65
+ default: 0,
66
+ }
67
+
68
+ has c: { # alternative syntax to be
69
+ is: :ro, # more similar to Moo/Moose
70
+ default: 1,
71
+ predicate: :can_haz_c?, # custom predicate
72
+ clearer: "desintegrate_c", # force coerce to symbol
73
+ }
74
+
75
+ has [:d, :e] => {
76
+ is: "ro", # can coerce from strings
77
+ default: 2,
78
+ }
79
+ end
80
+
81
+ class Proxy
82
+ include MooseX
83
+
84
+ has target: {
85
+ is: :ro,
86
+ default: lambda { Target.new }, # default, new instace of Target
87
+ handles: { # handles is for delegation,
88
+ my_method_x: :method_x, # inject methods with new names
89
+ my_method_y: :method_y, # old => obj.target.method_x
90
+ }, # now => obj.my_method_x
91
+ }
92
+ end
93
+
94
+ class Target
95
+ def method_x; 1024; end # works with simple methods
96
+ def method_y(a,b,c); a + b + c; end # or methods with arguments
97
+ end
98
+
99
+ # now you have a generic constructor
100
+ p1 = Point.new # x and y will be 0
101
+ p2 = Point.new( x: 5 ) # y will be 0
102
+ p3 = Point.new( x: 5, y: 4)
103
+ foo = Foo.new( bar: 123 ) # without bar will raise exception
104
+ baz = Baz.new( bam: 99 ) # if bam > 100 will raise exception
105
+ Proxy.new.my_method_x # will call method_x in target, return 1024
95
106
  ```
96
107
 
97
108
  ## Installation
@@ -108,10 +119,126 @@ Or install it yourself as:
108
119
 
109
120
  $ gem install moosex
110
121
 
111
- ## Usage
122
+ You need ruby 2.0.x or superior.
123
+
124
+ ## Description
112
125
 
113
126
  MooseX is an extension of Ruby object system. The main goal of MooseX is to make Ruby Object Oriented programming easier, more consistent, and less tedious. With MooseX you can think more about what you want to do and less about the mechanics of OOP. It is a port of Moose/Moo from Perl to Ruby world.
114
127
 
128
+ Read more about Moose on http://moose.iinteractive.com/en/
129
+
130
+ ## Motivation
131
+
132
+ It is fun
133
+
134
+ ## Usage
135
+
136
+ When you incluse the MooseX module in your class you can declare your attributes. The module provides a new constructor for you, you should not define 'initialize' anymore.
137
+
138
+
139
+ ```ruby
140
+ require 'moosex'
141
+
142
+ class Point
143
+ include MooseX
144
+
145
+ has x: {
146
+ is: :rw, # read-write (mandatory)
147
+ isa: Integer, # should be Integer
148
+ default: 0, # default value is 0 (constant)
149
+ required: false, # if true, will be required in the constructor
150
+ predicate: false, # if true, add has_x? method
151
+ clearer: false, # if true, add clear_x! method
152
+ handles: [ :to_s ],# used for method delegation
153
+ }
154
+ ...
155
+ end
156
+ ```
157
+
158
+ in this example we add the attribute x, with read-write acessors, a default value and a type check.
159
+
160
+ ```ruby
161
+ p1 = Point.new # x will be initialize with 0 (default)
162
+ p2 = Point.new(x: 50) # initialize x in the constructur
163
+ p3 = Point.new(x: "50") # will raise exception
164
+ p1.x = "lol" # will raise too
165
+ ```
166
+
167
+ to use the type check feature you must use the writter method for the attribute.
168
+
169
+ ### Advantages
170
+
171
+ instead
172
+ ```ruby
173
+ class Foo
174
+ attr_accessor :bar, :baz, :bam
175
+
176
+ def initialize(bar=0, baz=0, bam=0)
177
+ unless [bar, baz, bam].all? {|x| x.is_a? Integer }
178
+ raise "you should use only Integers to build Foo"
179
+ end
180
+ @bar = bar
181
+ @baz = baz
182
+ @bam = bam
183
+ end
184
+ end
185
+ ```
186
+ you can
187
+ ```ruby
188
+ class Foo
189
+ include MooseX
190
+
191
+ has [:bar, :baz, :bam], {
192
+ is: :rw,
193
+ isa: Integer,
194
+ default: 0
195
+ }
196
+ end
197
+ ```
198
+ instead
199
+ ```ruby
200
+ class Proxy
201
+ def initialize(target)
202
+ @target=target
203
+ end
204
+
205
+ def method_x(a,b,c)
206
+ @target.method_x(a,b,c)
207
+ end
208
+ def method_y(a,b,c)
209
+ @target.method_y(a,b,c)
210
+ end
211
+ end
212
+ ```
213
+ you can
214
+ ```ruby
215
+ class Proxy
216
+ include MooseX
217
+
218
+ has :target, {
219
+ is: :ro,
220
+ handles => [ :method_x, :method_y ]
221
+ }
222
+ end
223
+ ```
224
+ and much more
225
+
226
+ ## TODO
227
+
228
+ 1. Support to lazy attributes
229
+ 2. Support to BUILD and BUILDARGS hook
230
+ 3. Support to Roles ( it is a Module on Steroids )
231
+ 4. Support to after/before/around
232
+ 5. Improve the typecheck system (we should specify: we need an array of positive integers)
233
+ 6. Improve the exception and warning system
234
+ 7. Profit!
235
+
236
+ ## Limitations
237
+
238
+ Experimental module, be careful.
239
+
240
+ Now has limited support to subclassing.
241
+
115
242
  ## Contributing
116
243
 
117
244
  1. Fork it ( http://github.com/peczenyj/MooseX/fork )
data/Rakefile CHANGED
@@ -1,3 +1,3 @@
1
1
  require 'rspec/core/rake_task'
2
2
  RSpec::Core::RakeTask.new(:spec)
3
- task :default => :spec
3
+ task default: :spec
data/lib/moosex.rb CHANGED
@@ -7,11 +7,11 @@ require "moosex/version"
7
7
 
8
8
  module MooseX
9
9
 
10
- def self.included(o)
10
+ def MooseX.included(c)
11
11
 
12
- o.extend(MooseX::Core)
12
+ c.extend(MooseX::Core)
13
13
 
14
- o.class_exec do
14
+ c.class_exec do
15
15
  meta = MooseX::Meta.new
16
16
 
17
17
  define_singleton_method(:__meta) { meta }
@@ -22,9 +22,34 @@ module MooseX
22
22
  self.class.__meta().init(self, args)
23
23
 
24
24
  end
25
+
26
+ def c.inherited(subclass)
27
+ subclass.class_exec do
28
+ old_meta = subclass.__meta
29
+
30
+ meta = MooseX::Meta.new(old_meta.attrs)
31
+
32
+ define_singleton_method(:__meta) { meta }
33
+ end
34
+ end
25
35
 
26
36
  end
27
37
 
38
+ class Meta
39
+ attr_reader :attrs
40
+ def initialize(attrs=[])
41
+ @attrs = attrs.map{|att| att.clone }
42
+ end
43
+
44
+ def add(attr)
45
+ @attrs << attr
46
+ end
47
+
48
+ def init(object, args)
49
+ @attrs.each{ |attr| attr.init(object, args) }
50
+ end
51
+ end
52
+
28
53
  module Core
29
54
 
30
55
  def has(attr_name, attr_options = {})
@@ -63,32 +88,32 @@ module MooseX
63
88
 
64
89
  class Attribute
65
90
 
66
- attr_reader :attr_symbol, :is, :isa, :default, :required
67
-
91
+ attr_reader :attr_symbol, :is
68
92
  DEFAULTS= {
69
- :clearer => false,
70
- :required => false,
71
- :predicate => false,
72
- :isa => lambda { |x| true },
73
- :handles => {},
93
+ lazy: false,
94
+ clearer: false,
95
+ required: false,
96
+ predicate: false,
97
+ isa: lambda { |x| true },
98
+ handles: {},
74
99
  }
75
100
 
76
101
  REQUIRED = [ :is ]
77
102
 
78
103
  VALIDATE = {
79
- :is => lambda do |is, field_name|
104
+ is: lambda do |is, field_name|
80
105
  unless [:rw, :rwp, :ro, :lazy].include?(is)
81
106
  raise "invalid value for field '#{field_name}' is '#{is}', must be one of :rw, :rwp, :ro or :lazy"
82
107
  end
83
108
  end,
84
- :handles => lambda {|handles, field_name| true }, # TODO: add implementation
109
+ handles: lambda {|handles, field_name| true }, # TODO: add implementation
85
110
  };
86
111
 
87
112
  COERCE = {
88
- :is => lambda do |is, field_name|
113
+ is: lambda do |is, field_name|
89
114
  is.to_sym
90
115
  end,
91
- :isa => lambda do |isa, field_name|
116
+ isa: lambda do |isa, field_name|
92
117
  return isa if isa.is_a? Proc
93
118
 
94
119
  return lambda do |new_value|
@@ -97,15 +122,18 @@ module MooseX
97
122
  end
98
123
  end
99
124
  end,
100
- :default => lambda do |default, field_name|
125
+ default: lambda do |default, field_name|
101
126
  return default if default.is_a? Proc
102
127
 
103
128
  return lambda { default }
104
129
  end,
105
- :required => lambda do |required, field_name|
130
+ required: lambda do |required, field_name|
106
131
  !!required
107
132
  end,
108
- :predicate => lambda do |predicate, field_name|
133
+ lazy: lambda do |lazy, field_name|
134
+ !!lazy
135
+ end,
136
+ predicate: lambda do |predicate, field_name|
109
137
  if ! predicate
110
138
  return false
111
139
  elsif predicate.is_a? TrueClass
@@ -119,7 +147,7 @@ module MooseX
119
147
  raise "cannot coerce field predicate to a symbol for #{field_name}: #{e}"
120
148
  end
121
149
  end,
122
- :clearer => lambda do|clearer, field_name|
150
+ clearer: lambda do|clearer, field_name|
123
151
  if ! clearer
124
152
  return false
125
153
  elsif clearer.is_a? TrueClass
@@ -133,11 +161,44 @@ module MooseX
133
161
  raise "cannot coerce field clearer to a symbol for #{field_name}: #{e}"
134
162
  end
135
163
  end,
136
- :handles => lambda do |handles, field_name|
137
- # TODO:
138
- # if single method
139
- # if array of methods
140
- handles
164
+ handles: lambda do |handles, field_name|
165
+
166
+ unless handles.is_a? Hash
167
+
168
+ array_of_handles = handles
169
+
170
+ unless array_of_handles.is_a? Array
171
+ array_of_handles = [ array_of_handles ]
172
+ end
173
+
174
+ handles = array_of_handles.map do |handle|
175
+
176
+ if handle == BasicObject
177
+
178
+ raise "ops, should not use BasicObject for handles in #{field_name}"
179
+
180
+ elsif handle.is_a? Class
181
+
182
+ handle = handle.public_instance_methods - handle.superclass.public_instance_methods
183
+
184
+ elsif handle.is_a? Module
185
+
186
+ handle = handle.public_instance_methods
187
+
188
+ end
189
+
190
+ handle
191
+
192
+ end.flatten.reduce({}) do |hash, method_name|
193
+ hash.merge({ method_name => method_name })
194
+ end
195
+ end
196
+
197
+ handles.map do |key,value|
198
+ { key.to_sym => value.to_sym }
199
+ end.reduce({}) do |hash,e|
200
+ hash.merge(e)
201
+ end
141
202
  end,
142
203
  };
143
204
 
@@ -169,6 +230,7 @@ module MooseX
169
230
  @predicate = o[:predicate]
170
231
  @clearer = o[:clearer]
171
232
  @handles = o[:handles]
233
+ @lazy = o[:lazy]
172
234
  end
173
235
 
174
236
  def init(object, args)
@@ -200,10 +262,10 @@ module MooseX
200
262
 
201
263
  if args.has_key? @attr_symbol
202
264
  value = args[ @attr_symbol ]
203
- elsif @required
204
- raise "attr \"#{@attr_symbol}\" is required"
205
265
  elsif @default
206
266
  value = @default.call
267
+ elsif @required
268
+ raise "attr \"#{@attr_symbol}\" is required"
207
269
  else
208
270
  return
209
271
  end
@@ -242,18 +304,4 @@ module MooseX
242
304
  return @isa
243
305
  end
244
306
  end
245
-
246
- class Meta
247
- def initialize
248
- @attrs = []
249
- end
250
-
251
- def add(attr)
252
- @attrs << attr
253
- end
254
-
255
- def init(object, args)
256
- @attrs.each{ |attr| attr.init(object, args) }
257
- end
258
- end
259
307
  end
@@ -1,3 +1,3 @@
1
1
  module Moosex
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.7"
3
3
  end
data/moosex.gemspec CHANGED
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.required_ruby_version = '~> 2.0'
22
+
21
23
  spec.add_development_dependency "bundler", "~> 1.5"
22
24
  spec.add_development_dependency "rake"
23
25
  spec.add_development_dependency "rspec"
data/spec/moosex_spec.rb CHANGED
@@ -1,112 +1,25 @@
1
- #require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
1
  require 'moosex'
3
2
 
4
3
  class Point
5
4
  include MooseX
6
-
7
- has :x , {
8
- :is => :rw,
9
- :isa => Integer,
10
- :default => 0,
11
- }
12
-
13
- has :y , {
14
- :is => :rw,
15
- :isa => Integer,
16
- :default => lambda { 0 },
17
- }
18
-
19
- def clear
20
- self.x= 0
21
- self.y= 0
22
- end
23
- end
24
-
25
- class Foo
26
- include MooseX
27
-
28
- has :bar, {
29
- :is => :rwp,
30
- :isa => Integer,
31
- :required => true
32
- }
33
- end
34
-
35
- class Baz
36
- include MooseX
37
-
38
- has :bam, {
39
- :is => :ro,
40
- :isa => lambda {|bam| raise 'bam should be less than 100' if bam > 100},
41
- :required => true
42
- }
43
- has :boom, {
44
- :is => :rw,
45
- :predicate => true,
46
- :clearer => true,
47
- }
48
- end
49
-
50
- class Lol
51
- include MooseX
52
5
 
53
- has [:a, :b], {
54
- :is => :ro,
55
- :default => 0,
6
+ has x: {
7
+ is: :rw, # read-write (mandatory)
8
+ isa: Integer, # should be Integer
9
+ default: 0, # default value is 0 (constant)
56
10
  }
57
11
 
58
- has :c => {
59
- :is => :ro,
60
- :default => 1,
61
- :predicate => :has_option_c?,
62
- :clearer => "reset_option_c", # force coerce
12
+ has y: {
13
+ is: :rw,
14
+ isa: Integer,
15
+ default: lambda { 0 }, # you should specify a lambda
63
16
  }
64
17
 
65
- has [:d, :e] => {
66
- :is => "ro",
67
- :default => 2,
68
- }
69
- end
70
-
71
- class Target
72
- def method_x
73
- 1024
74
- end
75
-
76
- def method_y(a,b,c)
77
- a + b + c
78
- end
79
- end
80
-
81
- class Proxy
82
- include MooseX
83
-
84
- has :target, {
85
- :is => :ro,
86
- :isa => Target,
87
- :default => lambda { Target.new() },
88
- :handles => {
89
- :my_method_x => :method_x,
90
- :my_method_y => :method_y,
91
- },
92
- }
93
- end
94
-
95
- describe "Proxy" do
96
- it "should delegate method_x to the target" do
97
- p = Proxy.new
98
-
99
- p.target.method_x.should == 1024
100
- p.my_method_x.should == 1024
18
+ def clear
19
+ self.x= 0 # to run with type-check you must
20
+ self.y= 0 # use the setter instad @x=
101
21
  end
102
-
103
- it "should delegate method_y to the target" do
104
- p = Proxy.new
105
-
106
- p.target.method_y(1,2,3).should == 6
107
- p.my_method_y(1,2,3).should == 6
108
- end
109
- end
22
+ end
110
23
 
111
24
  describe "Point" do
112
25
  describe "should has an intelligent constructor" do
@@ -117,13 +30,13 @@ describe "Point" do
117
30
  end
118
31
 
119
32
  it "should initialize only y" do
120
- p = Point.new( :x => 5 )
33
+ p = Point.new( x: 5 )
121
34
  p.x.should == 5
122
35
  p.y.should be_zero
123
36
  end
124
37
 
125
38
  it "should initialize x and y" do
126
- p = Point.new( :x => 5, :y => 4)
39
+ p = Point.new( x: 5, y: 4)
127
40
  p.x.should == 5
128
41
  p.y.should == 4
129
42
  end
@@ -145,12 +58,12 @@ describe "Point" do
145
58
 
146
59
  it "for x, with type check" do
147
60
  expect {
148
- Point.new(:x => "lol")
61
+ Point.new(x: "lol")
149
62
  }.to raise_error('isa check for "x" failed: is not instance of Integer!')
150
63
  end
151
64
 
152
65
  it "clear should clean attributes" do
153
- p = Point.new( :x => 5, :y => 4)
66
+ p = Point.new( x: 5, y: 4)
154
67
  p.clear
155
68
  p.x.should be_zero
156
69
  p.y.should be_zero
@@ -158,6 +71,15 @@ describe "Point" do
158
71
  end
159
72
  end
160
73
 
74
+ class Foo
75
+ include MooseX
76
+
77
+ has bar: {
78
+ is: :rwp, # read-write-private (private setter)
79
+ required: true, # you should require in the constructor
80
+ }
81
+ end
82
+
161
83
  describe "Foo" do
162
84
  it "should require bar if necessary" do
163
85
  expect {
@@ -166,26 +88,44 @@ describe "Foo" do
166
88
  end
167
89
 
168
90
  it "should require bar if necessary" do
169
- foo = Foo.new( :bar => 123 )
91
+ foo = Foo.new( bar: 123 )
170
92
  foo.bar.should == 123
171
93
  end
172
94
 
173
95
  it "should not be possible update bar (setter private)" do
174
- foo = Foo.new( :bar => 123 )
96
+ foo = Foo.new( bar: 123 )
175
97
  expect {
176
98
  foo.bar = 1024
177
99
  }.to raise_error(NoMethodError)
178
100
  end
179
101
  end
180
102
 
103
+ class Baz
104
+ include MooseX
105
+
106
+ has bam: {
107
+ is: :ro, # read-only, you should specify in new only
108
+ isa: lambda do |bam| # you should add your own validator
109
+ raise 'bam should be less than 100' if bam > 100
110
+ end,
111
+ required: true,
112
+ }
113
+
114
+ has boom: {
115
+ is: :rw,
116
+ predicate: true, # add has_boom? method, ask if the attribute is unset
117
+ clearer: true, # add reset_boom! method, unset the attribute
118
+ }
119
+ end
120
+
181
121
  describe "Baz" do
182
122
  it "should require bam if necessary" do
183
- baz = Baz.new( :bam => 99 )
123
+ baz = Baz.new( bam: 99 )
184
124
  baz.bam.should == 99
185
125
  end
186
126
 
187
127
  it "should not be possible update baz (read only)" do
188
- baz = Baz.new( :bam => 99 )
128
+ baz = Baz.new( bam: 99 )
189
129
  expect {
190
130
  baz.bam = 1024
191
131
  }.to raise_error(NoMethodError)
@@ -193,12 +133,12 @@ describe "Baz" do
193
133
 
194
134
  it "should run the lambda isa" do
195
135
  expect {
196
- Baz.new( :bam => 199 )
136
+ Baz.new( bam: 199 )
197
137
  }.to raise_error(/bam should be less than 100/)
198
138
  end
199
139
 
200
140
  it "rw acessor should has nil value, supports predicate" do
201
- baz = Baz.new( :bam => 99 )
141
+ baz = Baz.new( bam: 99 )
202
142
 
203
143
  baz.has_boom?.should be_false
204
144
  baz.boom.should be_nil
@@ -208,7 +148,7 @@ describe "Baz" do
208
148
  end
209
149
 
210
150
  it "rw acessor should has nil value, supports clearer" do
211
- baz = Baz.new( :bam => 99, :boom => 0 )
151
+ baz = Baz.new( bam: 99, boom: 0 )
212
152
 
213
153
  baz.has_boom?.should be_true
214
154
  baz.boom.should be_zero
@@ -220,7 +160,7 @@ describe "Baz" do
220
160
  end
221
161
 
222
162
  it "should be possible call the clearer twice" do
223
- baz = Baz.new( :bam => 99, :boom => 0 )
163
+ baz = Baz.new( bam: 99, boom: 0 )
224
164
 
225
165
  baz.reset_boom!
226
166
  baz.reset_boom!
@@ -230,9 +170,31 @@ describe "Baz" do
230
170
  end
231
171
  end
232
172
 
173
+ class Lol
174
+ include MooseX
175
+
176
+ has [:a, :b], { # define attributes a and b
177
+ is: :ro, # with same set of properties
178
+ default: 0,
179
+ }
180
+
181
+ has c: { # alternative syntax to be
182
+ is: :ro, # more similar to Moo/Moose
183
+ default: 1,
184
+ predicate: :can_haz_c?, # custom predicate
185
+ clearer: "desintegrate_c", # force coerce to symbol
186
+ }
187
+
188
+ has [:d, :e] => {
189
+ is: "ro", # can coerce from strings
190
+ default: 2,
191
+ required: true,
192
+ }
193
+ end
194
+
233
195
  describe "Lol" do
234
196
  it "Lol should has five arguments" do
235
- lol = Lol.new(:a => 5, :d => -1)
197
+ lol = Lol.new(a: 5, d: -1)
236
198
  lol.a.should == 5
237
199
  lol.b.should be_zero
238
200
  lol.c.should == 1
@@ -241,10 +203,222 @@ describe "Lol" do
241
203
  end
242
204
 
243
205
  it "Lol should support custom predicate and clearer" do
244
- lol = Lol.new(:a => 5, :d => -1)
206
+ lol = Lol.new(a: 5, d: -1)
245
207
 
246
- lol.has_option_c?.should be_true
247
- lol.reset_option_c
248
- lol.has_option_c?.should be_false
208
+ lol.can_haz_c?.should be_true
209
+ lol.desintegrate_c
210
+ lol.can_haz_c?.should be_false
249
211
  end
250
- end
212
+ end
213
+
214
+ class ProxyToTarget
215
+ include MooseX
216
+
217
+ has target: {
218
+ is: :ro,
219
+ default: lambda { Target.new }, # default, new instace of Target
220
+ handles: { # handles is for delegation,
221
+ my_method_x: :method_x, # inject methods with new names
222
+ my_method_y: :method_y, # old => obj.target.method_x
223
+ }, # now => obj.my_method_x
224
+ }
225
+ end
226
+
227
+ module TargetModule
228
+ def method_x; 1024; end # works with simple methods
229
+ def method_y(a,b,c); a + b + c; end # or methods with arguments
230
+ end
231
+
232
+ class Target
233
+ include TargetModule
234
+ end
235
+
236
+ describe "ProxyToTarget" do
237
+ it "should delegate method_x to the target" do
238
+ p = ProxyToTarget.new
239
+
240
+ p.target.method_x.should == 1024
241
+ p.my_method_x.should == 1024
242
+ end
243
+
244
+ it "should delegate method_y to the target" do
245
+ p = ProxyToTarget.new
246
+
247
+ p.target.method_y(1,2,3).should == 6
248
+ p.my_method_y(1,2,3).should == 6
249
+ end
250
+ end
251
+
252
+ class ProxyToTargetUsingArrayOfMethods
253
+ include MooseX
254
+
255
+ has targetz: {
256
+ is: :ro,
257
+ default: lambda { Target.new },
258
+ handles: [
259
+ :method_x, :method_y # will inject all methods with same name
260
+ ]
261
+ }
262
+ end
263
+
264
+ describe "ProxyToTargetUsingArrayOfMethods" do
265
+ it "should delegate method_x to the target" do
266
+ p = ProxyToTargetUsingArrayOfMethods.new
267
+
268
+ p.targetz.method_x.should == 1024
269
+ p.method_x.should == 1024
270
+ end
271
+
272
+ it "should delegate method_y to the target" do
273
+ p = ProxyToTargetUsingArrayOfMethods.new
274
+
275
+ p.targetz.method_y(1,2,3).should == 6
276
+ p.method_y(1,2,3).should == 6
277
+ end
278
+ end
279
+
280
+ class ProxyToTargetUsingSingleMethod
281
+ include MooseX
282
+
283
+ has target: {
284
+ is: :ro,
285
+ default: lambda { Target.new },
286
+ handles: "method_x" # coerce to an array of symbols
287
+ }
288
+ end
289
+
290
+ describe "ProxyToTargetUsingSingleMethod" do
291
+ it "should delegate method_x to the target" do
292
+ p = ProxyToTargetUsingSingleMethod.new
293
+
294
+ p.target.method_x.should == 1024
295
+ p.method_x.should == 1024
296
+ end
297
+ end
298
+
299
+ class ProxyToTargetUsingModule
300
+ include MooseX
301
+
302
+ has target: {
303
+ is: :ro,
304
+ default: lambda { Target.new },
305
+ handles: TargetModule # will import all methods from module
306
+ }
307
+ end
308
+
309
+ describe "ProxyToTargetUsingModule" do
310
+ it "should delegate method_x to the target" do
311
+ p = ProxyToTargetUsingModule.new
312
+
313
+ p.target.method_x.should == 1024
314
+ p.method_x.should == 1024
315
+ end
316
+
317
+ it "should delegate method_y to the target" do
318
+ p = ProxyToTargetUsingModule.new
319
+
320
+ p.target.method_y(1,2,3).should == 6
321
+ p.method_y(1,2,3).should == 6
322
+ end
323
+ end
324
+
325
+ class ProxyToTargetUsingClass
326
+ include MooseX
327
+
328
+ has target: {
329
+ is: :ro,
330
+ default: lambda { Target.new },
331
+ handles: Target # will use only public methods on Target class
332
+ } # exclude methods from superclass
333
+ end
334
+
335
+ describe "ProxyToTargetUsingClass" do
336
+ it "should delegate method_x to the target" do
337
+ p = ProxyToTargetUsingClass.new
338
+
339
+ p.target.method_x.should == 1024
340
+ p.method_x.should == 1024
341
+ end
342
+
343
+ it "should delegate method_y to the target" do
344
+ p = ProxyToTargetUsingClass.new
345
+
346
+ p.target.method_y(1,2,3).should == 6
347
+ p.method_y(1,2,3).should == 6
348
+ end
349
+ end
350
+
351
+ class Point3D < Point
352
+
353
+ has x: { # override original attr!
354
+ is: :rw,
355
+ isa: Integer,
356
+ default: 1,
357
+ }
358
+
359
+ has z: {
360
+ is: :rw, # read-write (mandatory)
361
+ isa: Integer, # should be Integer
362
+ default: 0, # default value is 0 (constant)
363
+ }
364
+
365
+ def clear
366
+ self.x= 0 # to run with type-check you must
367
+ self.y= 0 # use the setter instad @x=
368
+ self.z= 0
369
+ end
370
+ end
371
+
372
+ describe "Point3D" do
373
+ describe "should has an intelligent constructor" do
374
+ it "without arguments, should initialize with default values" do
375
+ p = Point3D.new
376
+ p.x.should == 1
377
+ p.y.should be_zero
378
+ p.z.should be_zero
379
+ end
380
+
381
+ it "should initialize only y" do
382
+ p = Point3D.new( x: 5 )
383
+ p.x.should == 5
384
+ p.y.should be_zero
385
+ p.z.should be_zero
386
+ end
387
+
388
+ it "should initialize x and y" do
389
+ p = Point3D.new( x: 5, y: 4, z: 8)
390
+ p.x.should == 5
391
+ p.y.should == 4
392
+ p.z.should == 8
393
+ end
394
+ end
395
+
396
+ describe "should create a getter and a setter" do
397
+ it "for z" do
398
+ p = Point3D.new
399
+ p.z= 5
400
+ p.z.should == 5
401
+ end
402
+
403
+ it "for z, with type check" do
404
+ p = Point3D.new
405
+ expect {
406
+ p.z = "lol"
407
+ }.to raise_error('isa check for "z" failed: is not instance of Integer!')
408
+ end
409
+
410
+ it "for z, with type check" do
411
+ expect {
412
+ Point3D.new(z: "lol")
413
+ }.to raise_error('isa check for "z" failed: is not instance of Integer!')
414
+ end
415
+
416
+ it "clear should clean attributes" do
417
+ p = Point3D.new( x: 5, y: 4, z: 9)
418
+ p.clear
419
+ p.x.should be_zero
420
+ p.y.should be_zero
421
+ p.z.should be_zero
422
+ end
423
+ end
424
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moosex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Peczenyj
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-31 00:00:00.000000000 Z
11
+ date: 2014-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -84,9 +84,9 @@ require_paths:
84
84
  - lib
85
85
  required_ruby_version: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '2.0'
90
90
  required_rubygems_version: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - ">="