konstructor 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.
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