moosex 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
data/lib/moosex.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # Module MooseX
2
- # A postmodern object system for Ruby
2
+ # A postmodern object DSL for Ruby
3
+ #
4
+ # Author:: Tiago Peczenyj (mailto:tiago.peczenyj@gmail.com)
5
+ # Copyright:: Copyright (c) 2014 Tiago Peczenyj
6
+ # License:: MIT
3
7
  #
4
- # 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.
5
-
6
8
  require "moosex/version"
7
9
 
8
10
  module MooseX
@@ -17,16 +19,16 @@ module MooseX
17
19
  define_singleton_method(:__meta) { meta }
18
20
  end
19
21
 
20
- def initialize(args={})
21
- args = BUILDARGS(args)
22
-
23
- self.class.__meta().init(self, args)
22
+ def initialize(*args)
23
+ args = BUILDARGS(*args)
24
+
25
+ self.class.__meta().init(self, args || {})
24
26
 
25
27
  BUILD()
26
28
  end
27
29
 
28
- def BUILDARGS(args)
29
- args
30
+ def BUILDARGS(*args)
31
+ args[0]
30
32
  end
31
33
 
32
34
  def BUILD
@@ -74,20 +76,15 @@ module MooseX
74
76
 
75
77
  attr = MooseX::Attribute.new(attr_name, attr_options)
76
78
 
77
- g = attr.generate_getter
78
-
79
- define_method attr.reader, &g
80
-
81
- s = attr.generate_setter
82
-
83
- case attr.is
84
- when :rw
85
- define_method attr.writter, &s
86
-
87
- when :rwp
88
- define_method attr.writter, &s
89
-
79
+ attr.methods.each_pair do |method, proc|
80
+ define_method method, &proc
81
+ end
82
+
83
+ if attr.is.eql?(:rwp)
84
+ private attr.writter
85
+ elsif attr.is.eql?(:private)
90
86
  private attr.writter
87
+ private attr.reader
91
88
  end
92
89
 
93
90
  __meta.add(attr)
@@ -97,7 +94,7 @@ module MooseX
97
94
 
98
95
  class Attribute
99
96
 
100
- attr_reader :attr_symbol, :is, :reader, :writter, :lazy, :builder
97
+ attr_reader :attr_symbol, :is, :reader, :writter, :lazy, :builder, :methods
101
98
  DEFAULTS= {
102
99
  lazy: false,
103
100
  clearer: false,
@@ -113,8 +110,8 @@ module MooseX
113
110
 
114
111
  VALIDATE = {
115
112
  is: lambda do |is, field_name|
116
- unless [:rw, :rwp, :ro, :lazy].include?(is)
117
- raise "invalid value for field '#{field_name}' is '#{is}', must be one of :rw, :rwp, :ro or :lazy"
113
+ unless [:rw, :rwp, :ro, :lazy, :private].include?(is)
114
+ raise "invalid value for field '#{field_name}' is '#{is}', must be one of :private, :rw, :rwp, :ro or :lazy"
118
115
  end
119
116
  end,
120
117
  };
@@ -161,7 +158,7 @@ module MooseX
161
158
  if ! clearer
162
159
  return false
163
160
  elsif clearer.is_a? TrueClass
164
- return "reset_#{field_name}!".to_sym
161
+ return "clear_#{field_name}!".to_sym
165
162
  end
166
163
 
167
164
  begin
@@ -252,6 +249,7 @@ module MooseX
252
249
  };
253
250
 
254
251
  def initialize(a, o)
252
+ #o ||= {}
255
253
  # todo extract this to a framework, see issue #21 on facebook
256
254
  o = DEFAULTS.merge({
257
255
  reader: a,
@@ -276,13 +274,16 @@ module MooseX
276
274
  validate.call(o[field], a)
277
275
  end
278
276
 
279
- if o[:is].eql? :lazy
277
+ if o[:is].eql? :ro
278
+ o[:writter] = nil
279
+ elsif o[:is].eql? :lazy
280
280
  o[:lazy] = true
281
+ o[:writter] = nil
281
282
  end
282
283
 
283
284
  unless o[:lazy]
284
285
  o[:builder] = nil
285
- end
286
+ end
286
287
 
287
288
  @attr_symbol = a
288
289
  @is = o[:is]
@@ -299,35 +300,42 @@ module MooseX
299
300
  @init_arg = o[:init_arg]
300
301
  @trigger = o[:trigger]
301
302
  @coerce = o[:coerce]
302
- end
303
-
304
- def init(object, args)
305
- inst_variable_name = "@#{@attr_symbol}".to_sym
306
-
307
- value = nil
303
+ @methods = {}
308
304
 
309
- attr_symbol = @attr_symbol
310
- @handles.each_pair do | method, target_method |
311
- object.define_singleton_method method do |*args|
312
- self.send(attr_symbol).send(target_method, *args)
313
- end
305
+ if @reader
306
+ @methods[@reader] = generate_reader
314
307
  end
315
-
308
+
309
+ if @writter
310
+ @methods[@writter] = generate_writter
311
+ end
312
+ inst_variable_name = "@#{@attr_symbol}".to_sym
316
313
  if @predicate
317
- object.define_singleton_method @predicate do
314
+ @methods[@predicate] = Proc.new do
318
315
  instance_variable_defined? inst_variable_name
319
316
  end
320
317
  end
321
318
 
322
319
  if @clearer
323
- object.define_singleton_method @clearer do
320
+ @methods[@clearer] = Proc.new do
324
321
  if instance_variable_defined? inst_variable_name
325
322
  remove_instance_variable inst_variable_name
326
323
  end
327
324
  end
328
325
  end
329
-
326
+
327
+ attr_symbol = @attr_symbol
328
+ @handles.each_pair do | method, target_method |
329
+ @methods[method] = Proc.new do |*args|
330
+ self.send(attr_symbol).send(target_method, *args)
331
+ end
332
+ end
333
+ end
334
+
335
+ def init(object, args)
336
+ value = nil
330
337
  value_from_default = false
338
+
331
339
  if args.has_key? @init_arg
332
340
  value = args[ @init_arg ]
333
341
  elsif @default
@@ -347,11 +355,12 @@ module MooseX
347
355
  @trigger.call(object, value)
348
356
  end
349
357
 
358
+ inst_variable_name = "@#{@attr_symbol}".to_sym
350
359
  object.instance_variable_set inst_variable_name, value
351
-
352
360
  end
353
-
354
- def generate_getter
361
+
362
+ private
363
+ def generate_reader
355
364
  inst_variable_name = "@#{@attr_symbol}".to_sym
356
365
 
357
366
  builder = @builder
@@ -378,7 +387,7 @@ module MooseX
378
387
  end
379
388
  end
380
389
 
381
- def generate_setter
390
+ def generate_writter
382
391
  inst_variable_name = "@#{@attr_symbol}".to_sym
383
392
  coerce = @coerce
384
393
  type_check = @isa
@@ -1,3 +1,3 @@
1
1
  module Moosex
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
data/moosex.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Moosex::VERSION
9
9
  spec.authors = ["Tiago Peczenyj"]
10
10
  spec.email = ["tiago.peczenyj@gmail.com"]
11
- spec.summary = %q{A postmodern object system for Ruby}
12
- spec.description = %q{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.}
11
+ spec.summary = %q{A postmodern object DSL for Ruby}
12
+ spec.description = %q{MooseX is an extension of Ruby object DSL. 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.}
13
13
  spec.homepage = "http://github.com/peczenyj/MooseX"
14
14
  spec.license = "MIT"
15
15
 
data/samples/point.rb ADDED
@@ -0,0 +1,59 @@
1
+ require 'moosex'
2
+
3
+ class Point
4
+ include MooseX
5
+
6
+ has x: {
7
+ is: :rw, # read-write (mandatory)
8
+ isa: Integer, # should be Integer
9
+ default: 0, # default value is 0 (constant)
10
+ }
11
+
12
+ has y: {
13
+ is: :rw,
14
+ isa: Integer,
15
+ default: lambda { 0 }, # you should specify a lambda
16
+ }
17
+
18
+ def clear!
19
+ self.x= 0 # to run with type-check you must
20
+ self.y= 0 # use the setter instad @x=
21
+ end
22
+
23
+ def to_s
24
+ "Point[x=#{self.x}, y=#{self.y}]"
25
+ end
26
+ end
27
+
28
+ class Point3D < Point
29
+ has z: {
30
+ is: :rw, # read-write (mandatory)
31
+ isa: Integer, # should be Integer
32
+ default: 0, # default value is 0 (constant)
33
+ }
34
+
35
+ def clear!
36
+ self.x= 0 # to run with type-check you must
37
+ self.y= 0 # use the setter instad @x=
38
+ self.z= 0
39
+ end
40
+
41
+ def to_s
42
+ "Point[x=#{self.x}, y=#{self.y}, z=#{self.z}]"
43
+ end
44
+ end
45
+
46
+ p1 = Point.new(x: 4, y:5)
47
+ p2 = Point.new()
48
+ p3 = Point3D.new(x: 4, y:5, z:6)
49
+ p4 = Point3D.new(x: 4, y:5)
50
+ p5 = Point3D.new()
51
+
52
+ puts ">> objects"
53
+ puts p1, p2, p3, p4, p5
54
+
55
+ p1.clear!
56
+ p3.clear!
57
+
58
+ puts ">> clear"
59
+ puts p1, p3
data/spec/baz_spec.rb ADDED
@@ -0,0 +1,85 @@
1
+ require 'moosex'
2
+
3
+ class Baz
4
+ include MooseX
5
+
6
+ has bam: {
7
+ is: :ro, # read-only, you should specify in new only
8
+ isa: lambda do |bam| # you should add your own validator
9
+ raise 'bam should be less than 100' if bam > 100
10
+ end,
11
+ required: true,
12
+ }
13
+
14
+ has boom: {
15
+ is: :rw,
16
+ predicate: true, # add has_boom? method, ask if the attribute is unset
17
+ clearer: true, # add clear_boom! method, unset the attribute
18
+ }
19
+ end
20
+
21
+ describe "Baz" do
22
+ it "should require bam if necessary" do
23
+ baz = Baz.new( bam: 99 )
24
+ baz.bam.should == 99
25
+ end
26
+
27
+ it "should not be possible update baz (read only)" do
28
+ baz = Baz.new( bam: 99 )
29
+ expect {
30
+ baz.bam = 1024
31
+ }.to raise_error(NoMethodError)
32
+ end
33
+
34
+ it "should run the lambda isa" do
35
+ expect {
36
+ Baz.new( bam: 199 )
37
+ }.to raise_error(/bam should be less than 100/)
38
+ end
39
+
40
+ it "should inject methods in the class (predicate)" do
41
+ baz = Baz.new( bam: 99 )
42
+
43
+ baz.respond_to?(:has_boom?).should be_true
44
+ Baz.instance_methods.member?(:has_boom?).should be_true
45
+ end
46
+
47
+ it "should inject methods in the class (clearer)" do
48
+ baz = Baz.new( bam: 99 )
49
+
50
+ baz.respond_to?(:clear_boom!).should be_true
51
+ Baz.instance_methods.member?(:clear_boom!).should be_true
52
+ end
53
+
54
+ it "rw acessor should has nil value, supports predicate" do
55
+ baz = Baz.new( bam: 99 )
56
+
57
+ baz.has_boom?.should be_false
58
+ baz.boom.should be_nil
59
+ baz.boom= 0
60
+ baz.has_boom?.should be_true
61
+ baz.boom.should be_zero
62
+ end
63
+
64
+ it "rw acessor should has nil value, supports clearer" do
65
+ baz = Baz.new( bam: 99, boom: 0 )
66
+
67
+ baz.has_boom?.should be_true
68
+ baz.boom.should be_zero
69
+
70
+ baz.clear_boom!
71
+
72
+ baz.has_boom?.should be_false
73
+ baz.boom.should be_nil
74
+ end
75
+
76
+ it "should be possible call the clearer twice" do
77
+ baz = Baz.new( bam: 99, boom: 0 )
78
+
79
+ baz.clear_boom!
80
+ baz.clear_boom!
81
+
82
+ baz.has_boom?.should be_false
83
+ baz.boom.should be_nil
84
+ end
85
+ end
@@ -0,0 +1,23 @@
1
+ require 'moosex'
2
+
3
+ class BuildExample
4
+ include MooseX
5
+
6
+ has [:x, :y], {
7
+ is: :rw,
8
+ required: true,
9
+ }
10
+ def BUILD
11
+ if self.x == self.y
12
+ raise "invalid: you should use x != y"
13
+ end
14
+ end
15
+ end
16
+
17
+ describe "BuildExample" do
18
+ it "should raise exception on build" do
19
+ expect {
20
+ BuildExample.new(x: 0, y: 0)
21
+ }.to raise_error(/invalid: you should use x != y/)
22
+ end
23
+ end
@@ -0,0 +1,106 @@
1
+ require 'moosex'
2
+
3
+ class BuildArgsExample
4
+ include MooseX
5
+
6
+ has [:x, :y], {
7
+ is: :rw,
8
+ required: true,
9
+ }
10
+
11
+ def BUILDARGS(args)
12
+
13
+ args[:x] = 1024
14
+ args[:y] = - args[:y]
15
+
16
+ args
17
+ end
18
+ end
19
+
20
+ describe "BuildArgsExample" do
21
+ it "should create the object" do
22
+ ex = BuildArgsExample.new(x: 10, y: -2)
23
+ ex.x.should == 1024
24
+ ex.y.should == 2
25
+ end
26
+ end
27
+
28
+ class BuildArgsExample2
29
+ include MooseX
30
+
31
+ has [:x, :y], {
32
+ is: :rw,
33
+ required: true,
34
+ }
35
+
36
+ def BUILDARGS(x=4,y=8)
37
+ args = {}
38
+ args[:x] = x
39
+ args[:y] = y
40
+
41
+ args
42
+ end
43
+ end
44
+
45
+ describe "BuildArgsExample2" do
46
+ it "should create the object" do
47
+ ex = BuildArgsExample2.new(1,2)
48
+ ex.x.should == 1
49
+ ex.y.should == 2
50
+ end
51
+
52
+ it "should create the object II" do
53
+ ex = BuildArgsExample2.new(1)
54
+ ex.x.should == 1
55
+ ex.y.should == 8
56
+ end
57
+
58
+ it "should create the object III" do
59
+ ex = BuildArgsExample2.new()
60
+ ex.x.should == 4
61
+ ex.y.should == 8
62
+ end
63
+ end
64
+
65
+ class BuildArgsExample3
66
+ include MooseX
67
+
68
+ has [:x, :y], {
69
+ is: :rw,
70
+ required: true,
71
+ }
72
+
73
+ def BUILDARGS(x: 4,y: 8)
74
+ args = {}
75
+ args[:x] = x
76
+ args[:y] = y
77
+
78
+ args
79
+ end
80
+ end
81
+
82
+ describe "BuildArgsExample3" do
83
+ it "should create the object" do
84
+ ex = BuildArgsExample3.new(x: 1, y:2)
85
+ ex.x.should == 1
86
+ ex.y.should == 2
87
+ end
88
+
89
+ it "should create the object II" do
90
+ ex = BuildArgsExample3.new(x: 1)
91
+ ex.x.should == 1
92
+ ex.y.should == 8
93
+ end
94
+
95
+ it "should create the object III" do
96
+ ex = BuildArgsExample3.new()
97
+ ex.x.should == 4
98
+ ex.y.should == 8
99
+ end
100
+
101
+ it "should create the object III" do
102
+ ex = BuildArgsExample3.new(y: 6)
103
+ ex.x.should == 4
104
+ ex.y.should == 6
105
+ end
106
+ end