konstructor 0.2.0 → 0.3.0

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: c470538008607d588c03a3f68fefb7800a88f83b
4
- data.tar.gz: 6517dba98cd9ad1f387d9410dcbbc7d04b19accb
3
+ metadata.gz: 1a639335de2f050fdd01c8504178cc934204ada8
4
+ data.tar.gz: d6a81f610da6159060b39b9209a4a0913b2fe7c2
5
5
  SHA512:
6
- metadata.gz: 0f4bcbf89a42a476af95f78bc08f33d314696f8da99f7c2120f059931d693c4eee149fd39bc64fbec79897d626f2c720a5a85d4def50ddedeae31422492f25d8
7
- data.tar.gz: 0ff11473769c2673730bf80222699ee2501067c7cc4e37432a3ab14882ad005a45f75fd4188a6499998ae47460d8d626c80f93a8b2084df2db4e136f36433d5a
6
+ metadata.gz: ae74c9aedf9971bd55fd2d709014631f39d1cff931d3d460b8084f30de57fe881599b264c657aa5431178d2aea5fa900d6820bc32e76c9b6f91422788f0e7707
7
+ data.tar.gz: eb8be3d92e5c96bd2a15580f8ec1dde0bf5d0a0648f58eabec393d321e27ffc74f3871aa62e931074f2e52cec1f58bb065dec898390c5b3e23dae5a9595bd6a7
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  Konstructor is a small gem that gives you multiple
12
12
  constructors in Ruby.
13
13
 
14
- Use `konstructor` keyword to define constructors additional to the defaul one:
14
+ Use `konstructor` keyword to declare constructors additional to the defaul one:
15
15
  ```ruby
16
16
  class SomeClass
17
17
  konstructor
@@ -44,40 +44,43 @@ You can also install it without Bundler:
44
44
 
45
45
  $ gem install konstructor
46
46
 
47
- If you wish to manually include Konstructor in your classes only when
48
- you need it, see [Manual include](https://github.com/snovity/konstructor/wiki/Manual-include) page.
47
+ If you are a gem author or just wish to manually include `konstructor`
48
+ keyword in your classes only when you need it, see
49
+ [Manual include](https://github.com/snovity/konstructor/wiki/Manual-include) page.
49
50
 
50
51
  ## Usage
51
52
 
52
- In simplest form `konstructor` creates a constructor from the next method.
53
+ In its simplest form `konstructor` declaration creates a
54
+ constructor from the next method.
53
55
 
54
56
  ```ruby
55
- konstructor
56
- def create
57
- end
57
+ konstructor
58
+ def create
59
+ end
58
60
 
59
- konstructor
60
- def recreate
61
- end
61
+ konstructor
62
+ def recreate
63
+ end
62
64
  ```
63
65
 
64
66
  When method names are given, it creates constructors from
65
67
  those methods without affecting the next method.
66
68
 
67
69
  ```ruby
68
- konstructor :create, :recreate
70
+ konstructor :create, :recreate
69
71
 
70
- def not_constructor
71
- end
72
+ def not_constructor
73
+ end
72
74
 
73
- def create
74
- end
75
+ def create
76
+ end
75
77
 
76
- def recreate
77
- end
78
+ def recreate
79
+ end
78
80
  ```
79
81
 
80
- Call with method names can be placed anywhere in class definition.
82
+ Declaration with method names can be placed anywhere in
83
+ class definition.
81
84
 
82
85
  ```ruby
83
86
  def create
@@ -89,7 +92,7 @@ those methods without affecting the next method.
89
92
  end
90
93
  ```
91
94
 
92
- In all above cases the class will have the default constructor
95
+ In all above cases `SomeClass` will have the default constructor
93
96
  and two additional ones.
94
97
 
95
98
  ```ruby
@@ -98,18 +101,28 @@ those methods without affecting the next method.
98
101
  obj2 = SomeClass.recreate
99
102
  ```
100
103
 
101
- ### Same as default constructor
104
+ If you decide to remove the default Ruby constructor for some reason,
105
+ you can effectively do it by marking it as private using Ruby
106
+ method `private_class_method`:
107
+
108
+ ```ruby
109
+ class SomeClass
110
+ private_class_method :new
111
+ end
112
+ ```
113
+
114
+ #### Same as default constructor
102
115
 
103
- Additional constructors work exactly the same way as
104
- built-in Ruby constructor.
116
+ Additional constructors work exactly the same way as the default one.
105
117
 
106
118
  You can pass blocks to them.
107
119
 
108
120
  ```ruby
109
- konstructor
110
- def create(val)
111
- @val = yield val
112
- end
121
+ konstructor
122
+ def create(val)
123
+ @val = yield val
124
+ end
125
+ #...
113
126
 
114
127
  obj = SomeClass.create(3) { |v| v*3 }
115
128
  obj.val # 9
@@ -135,64 +148,45 @@ end
135
148
  obj = SomeSubclass.create(2, 3)
136
149
  obj.val # 6
137
150
  ```
138
- Once method is a marked as konstructor in hierarchy,
139
- it is always a konstructor.
140
-
141
- Methods inherited from superclasses can't become konstructors in
142
- subclasses. To achieve the effect, define a new method,
143
- mark it as konstructor and call the inherited one.
144
-
145
- ### Reserved names
146
-
147
- Using reserved method names `new` and `initialize` for additional
148
- constructor declaration will raise an error:
149
- ```ruby
150
- konstructor
151
- def initialize # raises Konstructor::ReservedNameError
152
- end
153
- ```
154
- or
155
- ```ruby
156
- konstructor
157
- def new # raises Konstructor::ReservedNameError
158
- end
159
- ```
160
-
161
- ### Defining konstructors in Modules
151
+ Once method is declared as `konstructor` in hierarchy,
152
+ it is always a constructor.
162
153
 
163
- Modules can't have konstructors. Use `ActiveSupport::Concern` and
164
- define konstructor in `included` block.
154
+ There are certain limitations to what can be declared as `konstructor`,
155
+ see
156
+ [Limitations page](https://github.com/snovity/konstructor/wiki/Limitations)
157
+ for details.
165
158
 
166
- ### Using with other gems
159
+ #### Using with other gems
167
160
 
168
161
  Konstructor doesn't affect other gems, including those
169
- that depend on metaprogramming, such as [rake](https://github.com/ruby/rake), [thor](https://github.com/erikhuda/thor), [contracts](https://github.com/egonSchiele/contracts.ruby), etc.
162
+ that depend on metaprogramming, such as
163
+ [rake](https://github.com/ruby/rake),
164
+ [thor](https://github.com/erikhuda/thor),
165
+ [contracts](https://github.com/egonSchiele/contracts.ruby), etc.
170
166
 
171
- For instnace, this is how Konstructor works with contracts gem:
167
+ For instnace, this is how Konstructor works with contracts:
172
168
  ```ruby
173
- class SomeClass
174
- konstructor
175
- Contract Num => SomeClass
176
- def create(some_number)
177
- @number = some_number
178
- end
179
- end
169
+ class SomeClass
170
+ konstructor
171
+ Contract Num => SomeClass
172
+ def create(some_number)
173
+ @number = some_number
174
+ end
175
+ end
180
176
  ```
181
177
 
182
178
  If you stumble upon a metaprogramming gem that
183
- conflicts with Konstructor, please [open an issue](https://github.com/snovity/konstructor/issues/new).
179
+ conflicts with Konstructor, please
180
+ [open an issue](https://github.com/snovity/konstructor/issues/new).
181
+
182
+ ## Details
184
183
 
185
- ### Removing default constructor
184
+ Ruby constructor is a pair consisting of public factory method defined
185
+ on a class and a private instance method. Therefore, to achieve
186
+ its goal `konstructor` marks instance method as private and defines a
187
+ corresponding public class method with the same name.
186
188
 
187
- You can effectively remove default Ruby constructor
188
- by marking it as private:
189
- ```ruby
190
- class SomeClass
191
- private_class_method :new
192
- end
193
- ```
194
-
195
- ## Performance
189
+ #### Performance
196
190
 
197
191
  Konstructor does all its work when class is being defined. Once class
198
192
  has been defined, it's just standard Ruby instance creation.
@@ -200,34 +194,9 @@ Therefore, there is no runtime performance penalty.
200
194
 
201
195
  Konstructor doesn't depend on other gems.
202
196
 
203
- ## Thread safety
197
+ #### Thread safety
204
198
 
205
199
  Konstructor is thread safe.
206
-
207
- ## Details
208
-
209
- Ruby constructor is a pair consisting of public factory method defined
210
- on a class and a private instance method. Therefore, to achieve
211
- its goal `konstructor` marks instance method as private and defines a
212
- corresponding public class method with the same name.
213
-
214
- You can check if certain instance method name has been declared as
215
- constructor or is a default constructor by running.
216
- ```ruby
217
- Konstructor.is?(SomeClass, :initialize) # true
218
- Konstructor.is?(SomeClass, :create) # true
219
- Konstructor.is?(SomeClass, :recreate) # true
220
- Konstructor.is?(SomeClass, :something_else) # false
221
- ```
222
-
223
- It will return true even if no such constructor has
224
- been defined yet. Like:
225
- ```ruby
226
- class SomeClass
227
- konstructor :create
228
- end
229
- ```
230
- Konstructor body may be supplied in subclasses.
231
200
 
232
201
  ## Contributing
233
202
 
@@ -10,7 +10,14 @@ module Konstructor
10
10
  class IncludeInModuleError < StandardError
11
11
  def initialize(base)
12
12
  super "Konstructor can't be included in module '#{base.name}' directly, " +
13
- "please, use ActiveSupport::Concern or included hook directly."
13
+ "please, use ActiveSupport::Concern or standard included hook."
14
+ end
15
+ end
16
+
17
+ class DeclaringInheritedError < StandardError
18
+ def initialize(name)
19
+ super "You are declaring an inherited method '#{name}' as konstructor, "
20
+ "this is not allowed."
14
21
  end
15
22
  end
16
23
 
@@ -29,9 +29,9 @@ module Konstructor
29
29
  if @next_method_is_konstructor
30
30
  @next_method_is_konstructor = false
31
31
  @konstructor_names << name
32
- define(name)
32
+ process_declaration(name)
33
33
  elsif declared?(name)
34
- define(name)
34
+ process_declaration(name)
35
35
  end
36
36
  end
37
37
 
@@ -58,29 +58,41 @@ module Konstructor
58
58
  @konstructor_names.concat(new_names)
59
59
 
60
60
  new_names.each do |name|
61
- if has_own_method?(name)
62
- define(name)
61
+ if method_in_hierarchy?(name)
62
+ process_declaration(name)
63
63
  else
64
- # not sure if konstructor ever will be defined,
65
- # but informing about the problem anyway
66
- validate_name(name)
64
+ # not sure if method will ever be defined,
65
+ # but validating its name anyway
66
+ validate_name!(name)
67
67
  end
68
68
  end
69
69
  end
70
70
 
71
- def has_own_method?(name)
72
- method_defined = @klass.method_defined?(name) || @klass.private_method_defined?(name)
73
- superclass_method_defined = @klass.respond_to?(:superclass) && (
74
- @klass.superclass.method_defined?(name) || @klass.superclass.private_method_defined?(name)
75
- )
76
- method_defined && !superclass_method_defined
71
+ def method_in_hierarchy?(name)
72
+ method_defined?(@klass, name)
73
+ end
74
+
75
+ def method_on_superclass?(name)
76
+ @klass.respond_to?(:superclass) && method_defined?(@klass.superclass, name)
77
+ end
78
+
79
+ def method_defined?(klass, name)
80
+ klass.method_defined?(name) || klass.private_method_defined?(name)
77
81
  end
78
82
 
79
83
  # this method is idempotent
80
- def define(name)
81
- validate_name(name)
84
+ def process_declaration(name)
85
+ validate_name!(name)
82
86
 
83
- # defining class method
87
+ if method_on_superclass?(name) && !declared_in_superclass?(name)
88
+ raise DeclaringInheritedError, name
89
+ end
90
+
91
+ define_factory(name)
92
+ mark_as_private(name)
93
+ end
94
+
95
+ def define_factory(name)
84
96
  @klass.instance_eval <<-RUBY, __FILE__, __LINE__ + 1
85
97
  def #{name}(*args, &block)
86
98
  instance = allocate
@@ -88,12 +100,13 @@ module Konstructor
88
100
  instance
89
101
  end
90
102
  RUBY
103
+ end
91
104
 
92
- # marking instance method as private
105
+ def mark_as_private(name)
93
106
  @klass.__send__(:private, name)
94
107
  end
95
108
 
96
- def validate_name(name)
109
+ def validate_name!(name)
97
110
  if Konstructor.reserved?(name)
98
111
  raise ReservedNameError, name
99
112
  end
@@ -1,3 +1,3 @@
1
1
  module Konstructor
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: konstructor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dima Lashkov