Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 612 lines (441 sloc) 13.277 kb
5763a5d @solnic Fix gem badge [ci skip]
authored
1 [gem]: https://rubygems.org/gems/virtus
5d9bb73 @solnic [ci skip] ...and now add missing variables
authored
2 [travis]: https://travis-ci.org/solnic/virtus
3 [gemnasium]: https://gemnasium.com/solnic/virtus
4 [codeclimate]: https://codeclimate.com/github/solnic/virtus
5 [coveralls]: https://coveralls.io/r/solnic/virtus
6e93a1e @solnic Update BADGES
authored
6 [inchpages]: http://inch-ci.org/github/solnic/virtus/
7
8 Virtus
9 ======
10
310e67a @solnic Update README.md
authored
11 [![Gem Version](https://badge.fury.io/rb/virtus.svg)][gem]
6e93a1e @solnic Update BADGES
authored
12 [![Build Status](https://travis-ci.org/solnic/virtus.svg?branch=master)][travis]
13 [![Dependency Status](https://gemnasium.com/solnic/virtus.png)][gemnasium]
14 [![Code Climate](https://codeclimate.com/github/solnic/virtus/badges/gpa.svg)][codeclimate]
15 [![Test Coverage](https://codeclimate.com/github/solnic/virtus/badges/coverage.svg)][codeclimate]
16 [![Inline docs](http://inch-ci.org/github/solnic/virtus.svg?branch=master)][inchpages]
5d9bb73 @solnic [ci skip] ...and now add missing variables
authored
17
50acbde @solnic Update README
authored
18 Virtus allows you to define attributes on classes, modules or class instances with
19 optional information about types, reader/writer method visibility and coercion
20 behavior. It supports a lot of coercions and advanced mapping of embedded objects
21 and collections.
22
23 You can use it in many different contexts like:
24
25 * Input parameter sanitization and coercion in web applications
26 * Mapping JSON to domain objects
27 * Encapsulating data-access in Value Objects
28 * Domain model prototyping
29
30 And probably more.
ceed87f @solnic README update
authored
31
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
32 Installation
33 ------------
ceed87f @solnic README update
authored
34
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
35 ``` terminal
36 $ gem install virtus
37 ```
ceed87f @solnic README update
authored
38
5273374 @senny pretty installation notes
senny authored
39 or in your **Gemfile**
ceed87f @solnic README update
authored
40
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
41 ``` ruby
ba8a6f4 @solnic Add information about EV to the README
authored
42 gem 'virtus'
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
43 ```
ceed87f @solnic README update
authored
44
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
45 Examples
46 --------
ceed87f @solnic README update
authored
47
be9930d @dkubb Add heading for class usage
dkubb authored
48 ### Using Virtus with Classes
49
49a71ad @craiglittle Fix a few things in the README
craiglittle authored
50 You can create classes extended with Virtus and define attributes:
ceed87f @solnic README update
authored
51
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
52 ``` ruby
53 class User
0cf747f @solnic Update README
authored
54 include Virtus.model
ceed87f @solnic README update
authored
55
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
56 attribute :name, String
57 attribute :age, Integer
58 attribute :birthday, DateTime
59 end
ceed87f @solnic README update
authored
60
e648e2f @blashca Make solnic's age correct as of today
blashca authored
61 user = User.new(:name => 'Piotr', :age => 31)
62 user.attributes # => { :name => "Piotr", :age => 31 }
9bfc2c6 @solnic README update
authored
63
710f757 @senny inline xmp-comments and use consistent spacing
senny authored
64 user.name # => "Piotr"
749e93e @solnic Add info about default values to README
authored
65
e648e2f @blashca Make solnic's age correct as of today
blashca authored
66 user.age = '31' # => 31
710f757 @senny inline xmp-comments and use consistent spacing
senny authored
67 user.age.class # => Fixnum
749e93e @solnic Add info about default values to README
authored
68
710f757 @senny inline xmp-comments and use consistent spacing
senny authored
69 user.birthday = 'November 18th, 1983' # => #<DateTime: 1983-11-18T00:00:00+00:00 (4891313/2,0/1,2299161)>
0d72026 @solnic Mention mass-assignment in README
authored
70
71 # mass-assignment
72 user.attributes = { :name => 'Jane', :age => 21 }
73 user.name # => "Jane"
74 user.age # => 21
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
75 ```
749e93e @solnic Add info about default values to README
authored
76
1cac14f @solnic Update README
authored
77 ### Cherry-picking extensions
78
79 ``` ruby
048439d @solnic Update README
authored
80 # include attribute DSL + constructor + mass-assignment
1cac14f @solnic Update README
authored
81 class User
048439d @solnic Update README
authored
82 include Virtus.model
1cac14f @solnic Update README
authored
83
84 attribute :name, String
85 end
86
048439d @solnic Update README
authored
87 user = User.new(:name => 'Piotr')
88 user.attributes = { :name => 'John' }
89 user.attributes
90 # => {:name => 'John'}
1cac14f @solnic Update README
authored
91
92 # include attribute DSL + constructor
93 class User
048439d @solnic Update README
authored
94 include Virtus.model(:mass_assignment => false)
1cac14f @solnic Update README
authored
95
96 attribute :name, String
97 end
98
99 User.new(:name => 'Piotr')
100
048439d @solnic Update README
authored
101 # include just the attribute DSL
1cac14f @solnic Update README
authored
102 class User
048439d @solnic Update README
authored
103 include Virtus.model(:constructor => false, :mass_assignment => false)
1cac14f @solnic Update README
authored
104
105 attribute :name, String
106 end
107
048439d @solnic Update README
authored
108 user = User.new
109 user.name = 'Piotr'
1cac14f @solnic Update README
authored
110 ```
111
be9930d @dkubb Add heading for class usage
dkubb authored
112 ### Using Virtus with Modules
96bffb4 @solnic Update README with modules and instances examples
authored
113
49a71ad @craiglittle Fix a few things in the README
craiglittle authored
114 You can create modules extended with Virtus and define attributes for later
96bffb4 @solnic Update README with modules and instances examples
authored
115 inclusion in your classes:
116
117 ```ruby
118 module Name
55ca44a @solnic Update README
authored
119 include Virtus.module
96bffb4 @solnic Update README with modules and instances examples
authored
120
121 attribute :name, String
122 end
123
124 module Age
9b5a8b2 @solnic Update README
authored
125 include Virtus.module(:coerce => false)
96bffb4 @solnic Update README with modules and instances examples
authored
126
127 attribute :age, Integer
128 end
129
130 class User
131 include Name, Age
132 end
133
55ca44a @solnic Update README
authored
134 user = User.new(:name => 'John', :age => 30)
96bffb4 @solnic Update README with modules and instances examples
authored
135 ```
136
28a01ee @solnic Fix headers in README
authored
137 ### Dynamically Extending Instances
96bffb4 @solnic Update README with modules and instances examples
authored
138
139 It's also possible to dynamically extend an object with Virtus:
140
141 ```ruby
142 class User
143 # nothing here
144 end
145
146 user = User.new
e16ce43 @solnic Another README update
authored
147 user.extend(Virtus.model)
96bffb4 @solnic Update README with modules and instances examples
authored
148 user.attribute :name, String
149 user.name = 'John'
150 user.name # => 'John'
151 ```
749e93e @solnic Add info about default values to README
authored
152
28a01ee @solnic Fix headers in README
authored
153 ### Default Values
749e93e @solnic Add info about default values to README
authored
154
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
155 ``` ruby
156 class Page
0cf747f @solnic Update README
authored
157 include Virtus.model
9bfc2c6 @solnic README update
authored
158
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
159 attribute :title, String
28a9840 @solnic Fix whitespace
authored
160
994e344 @solnic Update README.md
authored
161 # default from a singleton value (integer in this case)
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
162 attribute :views, Integer, :default => 0
51e420b @fgrehm Fix default values example
fgrehm authored
163
164 # default from a singleton value (boolean in this case)
165 attribute :published, Boolean, :default => false
166
994e344 @solnic Update README.md
authored
167 # default from a callable object (proc in this case)
4bb86d8 @senny fix a typo in the README to showoff the default values
senny authored
168 attribute :slug, String, :default => lambda { |page, attribute| page.title.downcase.gsub(' ', '-') }
51e420b @fgrehm Fix default values example
fgrehm authored
169
994e344 @solnic Update README.md
authored
170 # default from a method name as symbol
171 attribute :editor_title, String, :default => :default_editor_title
172
173 def default_editor_title
174 published? ? title : "UNPUBLISHED: #{title}"
175 end
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
176 end
9bfc2c6 @solnic README update
authored
177
51e420b @fgrehm Fix default values example
fgrehm authored
178 page = Page.new(:title => 'Virtus README')
179 page.slug # => 'virtus-readme'
180 page.views # => 0
181 page.published # => false
182 page.editor_title # => "UNPUBLISHED: Virtus README"
d2e8dbd @pewniak747 added #set_default instance method [#154]
pewniak747 authored
183
184 page.views = 10
8e54e66 @pewniak747 implement suggestions after review
pewniak747 authored
185 page.views # => 10
186 page.reset_attribute(:views) # => 0
187 page.views # => 0
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
188 ```
9bfc2c6 @solnic README update
authored
189
ead555b @solnic Add info about default values on dynamically extended objects (closes #3...
authored
190 ### Default values on dynamically extended instances
191
192 This requires you to set `:lazy` option because default values are set in the
193 constructor if it's set to false (which is the default setting):
194
195 ``` ruby
196 User = Class.new
197 user = User.new
198 user.extend(Virtus.model)
199 user.attribute :name, String, default: 'jane', lazy: true
200 user.name # => "jane"
201 ```
202
28a01ee @solnic Fix headers in README
authored
203 ### Embedded Value
ba8a6f4 @solnic Add information about EV to the README
authored
204
205 ``` ruby
206 class City
0cf747f @solnic Update README
authored
207 include Virtus.model
ba8a6f4 @solnic Add information about EV to the README
authored
208
209 attribute :name, String
210 end
211
212 class Address
0cf747f @solnic Update README
authored
213 include Virtus.model
ba8a6f4 @solnic Add information about EV to the README
authored
214
215 attribute :street, String
216 attribute :zipcode, String
217 attribute :city, City
218 end
219
220 class User
0cf747f @solnic Update README
authored
221 include Virtus.model
ba8a6f4 @solnic Add information about EV to the README
authored
222
223 attribute :name, String
224 attribute :address, Address
225 end
226
227 user = User.new(:address => {
228 :street => 'Street 1/2', :zipcode => '12345', :city => { :name => 'NYC' } })
229
230 user.address.street # => "Street 1/2"
231 user.address.city.name # => "NYC"
232 ```
233
28a01ee @solnic Fix headers in README
authored
234 ### Collection Member Coercions
e0147b8 @solnic Add examples of collection member coercions to the README
authored
235
236 ``` ruby
237 # Support "primitive" classes
238 class Book
0cf747f @solnic Update README
authored
239 include Virtus.model
e0147b8 @solnic Add examples of collection member coercions to the README
authored
240
241 attribute :page_numbers, Array[Integer]
242 end
243
244 book = Book.new(:page_numbers => %w[1 2 3])
245 book.page_numbers # => [1, 2, 3]
246
247 # Support EmbeddedValues, too!
248 class Address
0cf747f @solnic Update README
authored
249 include Virtus.model
e0147b8 @solnic Add examples of collection member coercions to the README
authored
250
251 attribute :address, String
252 attribute :locality, String
253 attribute :region, String
254 attribute :postal_code, String
255 end
256
257 class PhoneNumber
0cf747f @solnic Update README
authored
258 include Virtus.model
e0147b8 @solnic Add examples of collection member coercions to the README
authored
259
260 attribute :number, String
261 end
262
263 class User
0cf747f @solnic Update README
authored
264 include Virtus.model
e0147b8 @solnic Add examples of collection member coercions to the README
authored
265
266 attribute :phone_numbers, Array[PhoneNumber]
267 attribute :addresses, Set[Address]
268 end
269
270 user = User.new(
271 :phone_numbers => [
272 { :number => '212-555-1212' },
273 { :number => '919-444-3265' } ],
274 :addresses => [
275 { :address => '1234 Any St.', :locality => 'Anytown', :region => "DC", :postal_code => "21234" } ])
276
277 user.phone_numbers # => [#<PhoneNumber:0x007fdb2d3bef88 @number="212-555-1212">, #<PhoneNumber:0x007fdb2d3beb00 @number="919-444-3265">]
278
279 user.addresses # => #<Set: {#<Address:0x007fdb2d3be448 @address="1234 Any St.", @locality="Anytown", @region="DC", @postal_code="21234">}>
280 ```
281
47474ed @greyblake Add Hash attributes coercon example to README
greyblake authored
282 ### Hash attributes coercion
283
284 ``` ruby
285 class Package
0cf747f @solnic Update README
authored
286 include Virtus.model
47474ed @greyblake Add Hash attributes coercon example to README
greyblake authored
287
288 attribute :dimensions, Hash[Symbol => Float]
289 end
290
291 package = Package.new(:dimensions => { 'width' => "2.2", :height => 2, "length" => 4.5 })
34efa67 @solnic Fix typo in README
authored
292 package.dimensions # => { :width => 2.2, :height => 2.0, :length => 4.5 }
47474ed @greyblake Add Hash attributes coercon example to README
greyblake authored
293 ```
294
d238b7e @solnic Add a note about Boolean type (closes #234)
authored
295 ### IMPORTANT note about Boolean type
296
297 Be aware that some libraries may do a terrible thing and define a global Boolean
298 constant which breaks virtus' constant type lookup, if you see issues with the
299 boolean type you can workaround it like that:
300
301 ``` ruby
302 class User
303 include Virtus.model
304
305 attribute :admin, Axiom::Types::Boolean
306 end
307 ```
308
309 This will be improved in Virtus 2.0.
310
4ef7e85 @solnic Add a note about member class coercion
authored
311 ### IMPORTANT note about member coercions
312
313 Virtus performs coercions only when a value is being assigned. If you mutate the value later on using its own
314 interfaces then coercion won't be triggered.
315
316 Here's an example:
317
318 ``` ruby
319 class Book
0cf747f @solnic Update README
authored
320 include Virtus.model
92f2cd9 @dkubb Fix whitespace
dkubb authored
321
4ef7e85 @solnic Add a note about member class coercion
authored
322 attribute :title, String
323 end
324
325 class Library
0cf747f @solnic Update README
authored
326 include Virtus.model
92f2cd9 @dkubb Fix whitespace
dkubb authored
327
4ef7e85 @solnic Add a note about member class coercion
authored
328 attribute :books, Array[Book]
329 end
330
331 library = Library.new
332
333 # This will coerce Hash to a Book instance
334 library.books = [ { :title => 'Introduction to Virtus' } ]
335
336 # This WILL NOT COERCE the value because you mutate the books array with Array#<<
337 library.books << { :title => 'Another Introduction to Virtus' }
338 ```
339
340 A suggested solution to this problem would be to introduce your own class instead of using Array and implement
341 mutation methods that perform coercions. For example:
342
343 ``` ruby
344 class Book
0cf747f @solnic Update README
authored
345 include Virtus.model
92f2cd9 @dkubb Fix whitespace
dkubb authored
346
4ef7e85 @solnic Add a note about member class coercion
authored
347 attribute :title, String
348 end
349
350 class BookCollection < Array
351 def <<(book)
352 if book.kind_of?(Hash)
353 super(Book.new(book))
354 else
355 super
356 end
357 end
358 end
359
360 class Library
0cf747f @solnic Update README
authored
361 include Virtus.model
92f2cd9 @dkubb Fix whitespace
dkubb authored
362
4ef7e85 @solnic Add a note about member class coercion
authored
363 attribute :books, BookCollection[Book]
364 end
365
366 library = Library.new
367 library.books << { :title => 'Another Introduction to Virtus' }
368 ```
369
28a01ee @solnic Fix headers in README
authored
370 ### Value Objects
6d1a987 @solnic Add ValueObject info to README
authored
371
372 ``` ruby
373 class GeoLocation
0cf747f @solnic Update README
authored
374 include Virtus.value_object
6d1a987 @solnic Add ValueObject info to README
authored
375
0cf747f @solnic Update README
authored
376 values do
377 attribute :latitude, Float
378 attribute :longitude, Float
379 end
6d1a987 @solnic Add ValueObject info to README
authored
380 end
381
382 class Venue
0cf747f @solnic Update README
authored
383 include Virtus.value_object
6d1a987 @solnic Add ValueObject info to README
authored
384
0cf747f @solnic Update README
authored
385 values do
386 attribute :name, String
387 attribute :location, GeoLocation
388 end
6d1a987 @solnic Add ValueObject info to README
authored
389 end
390
391 venue = Venue.new(
392 :name => 'Pub',
393 :location => { :latitude => 37.160317, :longitude => -98.437500 })
394
710f757 @senny inline xmp-comments and use consistent spacing
senny authored
395 venue.location.latitude # => 37.160317
6d1a987 @solnic Add ValueObject info to README
authored
396 venue.location.longitude # => -98.4375
397
398 # Supports object's equality
399
400 venue_other = Venue.new(
401 :name => 'Other Pub',
402 :location => { :latitude => 37.160317, :longitude => -98.437500 })
403
404 venue.location === venue_other.location # => true
405 ```
406
47fb699 @solnic Update README
authored
407 ### Custom Coercions
ceed87f @solnic README update
authored
408
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
409 ``` ruby
410 require 'json'
ceed87f @solnic README update
authored
411
4789745 @solnic README update
authored
412 class Json < Virtus::Attribute
02145db @solnic Update README
authored
413 def coerce(value)
4789745 @solnic README update
authored
414 value.is_a?(::Hash) ? value : JSON.parse(value)
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
415 end
02145db @solnic Update README
authored
416 end
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
417
02145db @solnic Update README
authored
418 class User
0cf747f @solnic Update README
authored
419 include Virtus.model
ceed87f @solnic README update
authored
420
a325a23 @solnic Fix Json example in the README (closes #245)
authored
421 attribute :info, Json, default: {}
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
422 end
ceed87f @solnic README update
authored
423
02145db @solnic Update README
authored
424 user = User.new
710f757 @senny inline xmp-comments and use consistent spacing
senny authored
425 user.info = '{"email":"john@domain.com"}' # => {"email"=>"john@domain.com"}
426 user.info.class # => Hash
47fb699 @solnic Update README
authored
427
428 # With a custom attribute encapsulating coercion-specific configuration
4789745 @solnic README update
authored
429 class NoisyString < Virtus::Attribute
430 def coerce(value)
5093278 @solnic Update README.md
authored
431 value.to_s.upcase
47fb699 @solnic Update README
authored
432 end
433 end
434
435 class User
0cf747f @solnic Update README
authored
436 include Virtus.model
47fb699 @solnic Update README
authored
437
438 attribute :scream, NoisyString
439 end
440
441 user = User.new(:scream => 'hello world!')
442 user.scream # => "HELLO WORLD!"
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
443 ```
105d4b6 @solnic Add information about coercions to README file
authored
444
3bab6df @krisleech Adds an example of a 'private attribute' to the README
krisleech authored
445 ### Private Attributes
446
447 ``` ruby
448 class User
0cf747f @solnic Update README
authored
449 include Virtus.model
3bab6df @krisleech Adds an example of a 'private attribute' to the README
krisleech authored
450
451 attribute :unique_id, String, :writer => :private
452
453 def set_unique_id(id)
454 self.unique_id = id
455 end
456 end
457
458 user = User.new(:unique_id => '1234-1234')
459 user.unique_id # => nil
460
461 user.unique_id = '1234-1234' # => NoMethodError: private method `unique_id='
462
463 user.set_unique_id('1234-1234')
464 user.unique_id # => '1234-1234'
465 ```
466
54db3ce @hendricius add readme for overriding setters
hendricius authored
467 ### Overriding setters
468
469 ``` ruby
470 class User
471 include Virtus.model
472
473 attribute :name, String
474
475 def name=(new_name)
476 custom_name = nil
477 if new_name == "Godzilla"
478 custom_name = "Can't tell"
479 end
480 super custom_name || new_name
481 end
482 end
483
484 user = User.new(name: "Frank")
485 user.name # => 'Frank'
486
487 user = User.new(name: "Godzilla")
488 user.name # => 'Can't tell'
489
490 ```
491
bd69f9d @solnic Update README
authored
492 ## Strict Coercion Mode
493
49a71ad @craiglittle Fix a few things in the README
craiglittle authored
494 By default Virtus returns the input value even when it couldn't coerce it to the expected type.
bd69f9d @solnic Update README
authored
495 If you want to catch such cases in a noisy way you can use the strict mode in which
49a71ad @craiglittle Fix a few things in the README
craiglittle authored
496 Virtus raises an exception when it failed to coerce an input value.
bd69f9d @solnic Update README
authored
497
498 ``` ruby
499 class User
9b5a8b2 @solnic Update README
authored
500 include Virtus.model(:strict => true)
bd69f9d @solnic Update README
authored
501
502 attribute :admin, Boolean
503 end
504
505 # this will raise an error
506 User.new :admin => "can't really say if true or false"
507 ```
508
a833a98 @lucasmazza Add The `nullify_blank` option to nullify empty Strings when coercion fa...
lucasmazza authored
509 ## Nullify Blank Strings Mode
510
511 If you want to replace empty Strings with `nil` values (since they can't be
512 coerced into the expected type), you can use the `:nullify_blank` option.
513
514 ``` ruby
515 class User
516 include Virtus.model(:nullify_blank => true)
517
518 attribute :birthday, Date
519 end
520
521 User.new(:birthday => "").birthday # => nil
522 ```
523
524
4b83e2c @solnic Update README.md
authored
525 ## Building modules with custom configuration
526
18fc0ef @elskwid Update README and docs
elskwid authored
527 You can also build Virtus modules that contain their own configuration.
528
529 ```ruby
0cf747f @solnic Update README
authored
530 YupNopeBooleans = Virtus.model { |mod|
18fc0ef @elskwid Update README and docs
elskwid authored
531 mod.coerce = true
ab4febf @lfender6445 Fix boolean_map example in readme
lfender6445 authored
532 mod.coercer.config.string.boolean_map = { 'nope' => false, 'yup' => true }
18fc0ef @elskwid Update README and docs
elskwid authored
533 }
534
535 class User
536 include YupNopeBooleans
537
538 attribute :name, String
539 attribute :admin, Boolean
540 end
541
542 # Or just include the module straight away ...
543 class User
9b5a8b2 @solnic Update README
authored
544 include Virtus.model(:coerce => false)
18fc0ef @elskwid Update README and docs
elskwid authored
545
546 attribute :name, String
547 attribute :admin, Boolean
548 end
549 ```
550
536e0d6 @solnic Update README
authored
551 ## Attribute Finalization and Circular Dependencies
552
553 If a type references another type which happens to not be available yet you need
051e77f @dkubb Fix whitespace
dkubb authored
554 to use lazy-finalization of attributes and finalize virtus manually after all
536e0d6 @solnic Update README
authored
555 types have been already loaded:
556
557 ``` ruby
558 # in blog.rb
559 class Blog
560 include Virtus.model(:finalize => false)
561
562 attribute :posts, Array['Post']
563 end
564
565 # in post.rb
566 class Post
567 include Virtus.model(:finalize => false)
568
569 attribute :blog, 'Blog'
570 end
571
572 # after loading both files just do:
573 Virtus.finalize
574
575 # constants will be resolved:
576 Blog.attribute_set[:posts].member_type.primitive # => Post
577 Post.attribute_set[:blog].type.primitive # => Blog
578 ```
579
bbdde04 @solnic Add a list of supported rubies to README
authored
580 Ruby version support
581 --------------------
582
583 Virtus is known to work correctly with the following rubies:
584
585 * 1.9.3
586 * 2.0.0
587 * 2.1.2
588 * jruby
589 * (probably) rbx
590
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
591 Credits
592 -------
ddcc8c1 @solnic Add contributors section to README
authored
593
594 * Dan Kubb ([dkubb](https://github.com/dkubb))
e5d155e @solnic Oops, sorry Chris :)
authored
595 * Chris Corbyn ([d11wtq](https://github.com/d11wtq))
ddcc8c1 @solnic Add contributors section to README
authored
596 * Emmanuel Gomez ([emmanuel](https://github.com/emmanuel))
4186272 @solnic Add fgrehm and mbj to the credits list
authored
597 * Fabio Rehm ([fgrehm](https://github.com/fgrehm))
0ece1f9 @solnic Add Ryan to the list of the awesome contributors!
authored
598 * Ryan Closner ([rclosner](https://github.com/rclosner))
4186272 @solnic Add fgrehm and mbj to the credits list
authored
599 * Markus Schirp ([mbj](https://github.com/mbj))
47b8c5a @solnic Add Yves Senn to the list of contributors
authored
600 * Yves Senn ([senny](https://github.com/senny))
ddcc8c1 @solnic Add contributors section to README
authored
601
4306df1 Using syntax highlighting, clarifying source.
Kurtis Rainbolt-Greene authored
602 Contributing
603 -------------
ceed87f @solnic README update
authored
604
605 * Fork the project.
606 * Make your feature addition or bug fix.
607 * Add tests for it. This is important so I don't break it in a
608 future version unintentionally.
319d1c5 @senny rephrased contribution guidelines to match the project structure
senny authored
609 * Commit, do not mess with Rakefile or version
ceed87f @solnic README update
authored
610 (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
611 * Send me a pull request. Bonus points for topic branches.
Something went wrong with that request. Please try again.