7ecced3a3b68584cdcd68f5e9e79b4950368e92a — Tim Morgan 1 year, 5 months ago b961e7a
Add more docs
3 files changed, 132 insertions(+), 8 deletions(-)

A LICENSE
M README.md
M src/lib.rs
A LICENSE => LICENSE +21 -0
@@ 0,0 1,21 @@
+MIT License
+
+Copyright (c) 2018 Tim Morgan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

M README.md => README.md +62 -0
@@ 6,6 6,62 @@
 
 Any heap-allocated struct, enum, or whatever should work.
 
+## Example
+
+```
+extern crate ruby_sys;
+extern crate ruby_wrap_data;
+
+use ruby_sys::{
+    class::{rb_class_new_instance, rb_define_class},
+    rb_cObject,
+    types::Value,
+    value::RubySpecialConsts::{Nil},
+    vm::ruby_init
+};
+
+use std::ffi::CString;
+use std::mem;
+
+const RB_NIL: Value = Value { value: Nil as usize };
+
+struct MyValue {
+    pub val: u16
+}
+
+fn alloc(klass: Value) -> Value {
+    // build your data and put it on the heap
+    let data = Box::new(MyValue { val: 1 });
+    // call `wrap()`, passing your klass and data
+    ruby_wrap_data::wrap(klass, data)
+}
+
+fn main() {
+    // you may need to start the ruby vm
+    unsafe { ruby_init() };
+
+    // create a ruby class and attach your alloc function
+    let name = CString::new("Thing").unwrap().into_raw();
+    let klass = unsafe { rb_define_class(name, rb_cObject) };
+    ruby_wrap_data::define_alloc_func(klass, alloc);
+
+    // create a new instance of the class
+    let thing = unsafe { rb_class_new_instance(0, &RB_NIL, klass) };
+
+    // get the data out of the ruby object
+    let data: Option<Box<MyValue>> = ruby_wrap_data::remove(thing);
+    assert!(data.is_some());
+
+    // if you try to remove it again, you get None
+    let data: Option<Box<MyValue>> = ruby_wrap_data::remove(thing);
+    assert!(data.is_none());
+
+    // set new data on the object
+    let new_data = Box::new(MyValue { val : 2 });
+    ruby_wrap_data::set(thing, new_data);
+}
+```
+
 ## Testing
 
 Assuming you're using rbenv (if not, sorry, you're on your own):


@@ 21,3 77,9 @@
 export LD_LIBRARY_PATH=$HOME/.rbenv/versions/2.5.1/lib
 RUBY=$(rbenv which ruby) cargo test
 ```
+
+## Copyright and License
+
+Copyright Tim Morgan
+
+Licensed MIT

M src/lib.rs => src/lib.rs +49 -8
@@ 8,7 8,7 @@
 //!
 //! ## Example
 //!
-//! ```
+//! ```rust
 //! extern crate ruby_sys;
 //! extern crate ruby_wrap_data;
 //!


@@ 49,7 49,12 @@
 //!     let thing = unsafe { rb_class_new_instance(0, &RB_NIL, klass) };
 //!
 //!     // get the data out of the ruby object
-//!     let data: Box<MyValue> = ruby_wrap_data::remove(thing).unwrap();
+//!     let data: Option<Box<MyValue>> = ruby_wrap_data::remove(thing);
+//!     assert!(data.is_some());
+//!
+//!     // if you try to remove it again, you get None
+//!     let data: Option<Box<MyValue>> = ruby_wrap_data::remove(thing);
+//!     assert!(data.is_none());
 //!
 //!     // set new data on the object
 //!     let new_data = Box::new(MyValue { val : 2 });


@@ 91,17 96,41 @@
     unsafe { rb_define_alloc_func(klass, alloc as CallbackPtr) };
 }
 
+/// Creates a new instance of the given class, wrapping the given
+/// heap-allocated data type.
+///
+/// # Arguments
+///
+/// * `klass` - a Ruby Class
+/// * `data`  - a Box<T> - the data you wish to embed in the Ruby object
 pub fn wrap<T>(klass: Value, data: Box<T>) -> Value {
     let datap = Box::into_raw(data) as *mut c_void;
     unsafe { rb_data_object_wrap(klass, datap, None, Some(free::<T>)) }
 }
 
-extern "C" fn free<T>(data: *mut c_void) {
-    // memory is freed when the box goes out of the scope
-    let datap = data as *mut T;
-    unsafe { Box::from_raw(datap) };
-}
-
+/// Removes and returns the wrapped data from the given Ruby object.
+/// Returns None if the data is currently NULL.
+///
+/// # Arguments
+///
+/// * `object` - a Ruby object
+///
+/// # Notes
+///
+/// You will need to specify the data type of the variable since it
+/// cannot be inferred:
+///
+/// ```compile_fail
+/// let data: Option<Box<MyValue>> = ruby_wrap_data::remove(thing);
+/// ```
+///
+/// Also note, if you wish to peek at the data without removing it,
+/// you will need to put it back using `set`, like this:
+///
+/// ```compile_fail
+/// let data: Option<Box<MyValue>> = ruby_wrap_data::remove(thing);
+/// ruby_wrap_data::set(thing, data.unwrap());
+/// ```
 pub fn remove<T>(object: Value) -> Option<Box<T>> {
     let rdata = rdata(object);
     let datap = unsafe { (*rdata).data as *mut T };


@@ 113,12 142,24 @@
     }
 }
 
+/// Sets the wrapped data on the given Ruby object.
+///
+/// # Arguments
+///
+/// * `object` - a Ruby object
+/// * `data`   - a Box<T> - the data you wish to embed in the Ruby object
 pub fn set<T>(object: Value, data: Box<T>) {
     let rdata = rdata(object);
     let datap = Box::into_raw(data) as *mut c_void;
     unsafe { (*rdata).data = datap };
 }
 
+extern "C" fn free<T>(data: *mut c_void) {
+    // memory is freed when the box goes out of the scope
+    let datap = data as *mut T;
+    unsafe { Box::from_raw(datap) };
+}
+
 fn set_none(object: Value) {
     let rdata = rdata(object);
     unsafe { (*rdata).data = ptr::null_mut() };