Skip to content
Merged

Dev #392

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rice/Data_Type.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ namespace Rice
template <typename Attribute_T, typename Access_T, typename...Arg_Ts>
inline Data_Type<T>& Data_Type<T>::define_singleton_attr(std::string name, Attribute_T attribute, Access_T access, const Arg_Ts&...args)
{
VALUE singleton = detail::protect(rb_singleton_class, this->value());
VALUE singleton = detail::protect(rb_singleton_class, this->validated_value());
return this->define_attr_internal<Attribute_T, Access_T>(singleton, name, std::forward<Attribute_T>(attribute), access, args...);
}

Expand Down
15 changes: 10 additions & 5 deletions rice/cpp_api/Object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,19 @@ namespace Rice
Object(Object&& other) = default;
Object& operator=(Object&& other) = default;

//! Implicit conversion to VALUE.
operator VALUE() const;

//! Explicitly get the encapsulated VALUE.
VALUE value() const;

//! Returns false if the object is nil or false; returns true
//! otherwise.
explicit operator bool() const;

//! Returns true if the object is nil, false otherwise.
bool is_nil() const;

//! Implicit conversion to VALUE.
operator VALUE() const;

//! Explicitly get the encapsulated VALUE.
VALUE value() const;

//! Get the class of an object.
/*! \return the object's Class.
Expand Down Expand Up @@ -249,6 +250,10 @@ namespace Rice
void remove_const(Identifier name);

protected:
//! Checks the encapsulated VALUE is not nil and returns it. If it is nil
//! an exception is thrown.
VALUE validated_value() const;

//! Set the encapsulated value.
void set_value(VALUE value);

Expand Down
70 changes: 39 additions & 31 deletions rice/cpp_api/Object.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,19 @@ namespace Rice
{
}

inline Object::operator bool() const
{
// Bypass getter to not raise exception
return RTEST(this->value_.value());
}

inline bool Object::is_nil() const
inline VALUE Object::value() const
{
// Bypass getter to not raise exception
return NIL_P(this->value_.value());
return this->value_.value();
}

inline Object::operator VALUE() const
{
return this->value();
}

inline VALUE Object::value() const
inline VALUE Object::validated_value() const
{
VALUE result = this->value_.value();
VALUE result = this->value();

if (result == Qnil)
{
Expand All @@ -38,6 +31,16 @@ namespace Rice
return result;
}

inline Object::operator bool() const
{
return RTEST(this->value());
}

inline bool Object::is_nil() const
{
return NIL_P(this->value());
}

template<typename ...Parameter_Ts>
inline Object Object::call(Identifier id, Parameter_Ts... args) const
{
Expand All @@ -49,21 +52,21 @@ namespace Rice
easy to duplicate by setting GC.stress to true and calling a constructor
that takes multiple values like a std::pair wrapper. */
std::array<VALUE, sizeof...(Parameter_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Parameter_Ts>>().convert(std::forward<Parameter_Ts>(args))... };
return detail::protect(rb_funcallv, value(), id.id(), (int)values.size(), (const VALUE*)values.data());
return detail::protect(rb_funcallv, this->validated_value(), id.id(), (int)values.size(), (const VALUE*)values.data());
}

template<typename ...Parameter_Ts>
inline Object Object::call_kw(Identifier id, Parameter_Ts... args) const
{
/* IMPORTANT - See call() above */
std::array<VALUE, sizeof...(Parameter_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Parameter_Ts>>().convert(args)... };
return detail::protect(rb_funcallv_kw, value(), id.id(), (int)values.size(), (const VALUE*)values.data(), RB_PASS_KEYWORDS);
return detail::protect(rb_funcallv_kw, this->validated_value(), id.id(), (int)values.size(), (const VALUE*)values.data(), RB_PASS_KEYWORDS);
}

template<typename T>
inline void Object::iv_set(Identifier name, T const& value)
{
detail::protect(rb_ivar_set, this->value(), name.id(), detail::To_Ruby<T>().convert(value));
detail::protect(rb_ivar_set, this->validated_value(), name.id(), detail::To_Ruby<T>().convert(value));
}

inline int Object::compare(Object const& other) const
Expand All @@ -79,66 +82,71 @@ namespace Rice
return this->is_nil() && other.is_nil();
}

VALUE result = detail::protect(rb_equal, this->value(), other.value());
VALUE result = detail::protect(rb_equal, this->validated_value(), other.validated_value());
return RB_TEST(result);
}

inline bool Object::is_eql(const Object& other) const
{
VALUE result = detail::protect(rb_eql, this->value(), other.value());
if (this->is_nil() || other.is_nil())
{
return this->is_nil() && other.is_nil();
}

VALUE result = detail::protect(rb_eql, this->validated_value(), other.validated_value());
return RB_TEST(result);
}

inline void Object::freeze()
{
detail::protect(rb_obj_freeze, value());
detail::protect(rb_obj_freeze, this->validated_value());
}

inline bool Object::is_frozen() const
{
return RB_OBJ_FROZEN(value());
return RB_OBJ_FROZEN(this->validated_value());
}

inline int Object::rb_type() const
{
return ::rb_type(this->value());
return ::rb_type(this->validated_value());
}

inline VALUE Object::object_id() const
{
return detail::protect(rb_obj_id, this->value());
return detail::protect(rb_obj_id, this->validated_value());
}

inline bool Object::is_a(Object klass) const
{
VALUE result = detail::protect(rb_obj_is_kind_of, this->value(), klass.value());
VALUE result = detail::protect(rb_obj_is_kind_of, this->validated_value(), klass.validated_value());
return RB_TEST(result);
}

inline void Object::extend(Module const& mod)
{
detail::protect(rb_extend_object, this->value(), mod.value());
detail::protect(rb_extend_object, this->validated_value(), mod.validated_value());
}

inline bool Object::respond_to(Identifier id) const
{
return bool(rb_respond_to(this->value(), id.id()));
return bool(rb_respond_to(this->validated_value(), id.id()));
}

inline bool Object::is_instance_of(Object klass) const
{
VALUE result = detail::protect(rb_obj_is_instance_of, this->value(), klass.value());
VALUE result = detail::protect(rb_obj_is_instance_of, this->validated_value(), klass.validated_value());
return RB_TEST(result);
}

inline Object Object::iv_get(Identifier name) const
{
return detail::protect(rb_ivar_get, this->value(), name.id());
return detail::protect(rb_ivar_get, this->validated_value(), name.id());
}

inline Object Object::attr_get(Identifier name) const
{
return detail::protect(rb_attr_get, this->value(), name.id());
return detail::protect(rb_attr_get, this->validated_value(), name.id());
}

inline void Object::set_value(VALUE value)
Expand All @@ -148,20 +156,20 @@ namespace Rice

inline Object Object::const_get(Identifier name) const
{
return detail::protect(rb_const_get, this->value(), name.id());
return detail::protect(rb_const_get, this->validated_value(), name.id());
}

inline bool Object::const_defined(Identifier name) const
{
size_t result = detail::protect(rb_const_defined, this->value(), name.id());
size_t result = detail::protect(rb_const_defined, this->validated_value(), name.id());
return bool(result);
}

inline Object Object::const_set(Identifier name, Object value)
{
// We will allow setting constants to Qnil, or the decimal value of 4. This happens
// in C++ libraries with enums. Thus skip the value() method that raises excptions
detail::protect(rb_const_set, this->value(), name.id(), value.value_.value());
// in C++ libraries with enums. Thus use value() instead of validated_value
detail::protect(rb_const_set, this->validated_value(), name.id(), value.value());
return value;
}

Expand All @@ -176,7 +184,7 @@ namespace Rice

inline void Object::remove_const(Identifier name)
{
detail::protect(rb_mod_remove_const, this->value(), name.to_sym());
detail::protect(rb_mod_remove_const, this->validated_value(), name.to_sym());
}

inline bool operator==(Object const& lhs, Object const& rhs)
Expand Down
8 changes: 4 additions & 4 deletions rice/cpp_api/String.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,22 @@ namespace Rice

inline size_t String::length() const
{
return RSTRING_LEN(value());
return RSTRING_LEN(this->value());
}

inline char String::operator[](ptrdiff_t index) const
{
return RSTRING_PTR(value())[index];
return RSTRING_PTR(this->value())[index];
}

inline char const* String::c_str() const
{
return RSTRING_PTR(value());
return RSTRING_PTR(this->value());
}

inline std::string String::str() const
{
return std::string(RSTRING_PTR(value()), length());
return std::string(RSTRING_PTR(this->value()), length());
}

template<typename T>
Expand Down
8 changes: 4 additions & 4 deletions rice/cpp_api/shared_methods.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/
inline auto& include_module(Module const& inc)
{
detail::protect(rb_include_module, this->value(), inc.value());
detail::protect(rb_include_module, this->validated_value(), inc.value());
return *this;
}

Expand All @@ -33,7 +33,7 @@ inline auto& include_module(Module const& inc)
template<typename Method_T, typename...Arg_Ts>
inline auto& define_method(std::string name, Method_T&& method, const Arg_Ts&...args)
{
this->wrap_native_method(this->value(), name, std::forward<Method_T>(method), args...);
this->wrap_native_method(this->validated_value(), name, std::forward<Method_T>(method), args...);
return *this;
}

Expand All @@ -51,7 +51,7 @@ inline auto& define_method(std::string name, Method_T&& method, const Arg_Ts&...
template<typename Function_T, typename...Arg_Ts>
inline auto& define_function(std::string name, Function_T&& func, const Arg_Ts&...args)
{
this->wrap_native_function(this->value(), name, std::forward<Function_T>(func), args...);
this->wrap_native_function(this->validated_value(), name, std::forward<Function_T>(func), args...);
return *this;
}

Expand Down Expand Up @@ -125,6 +125,6 @@ template<typename Constant_T>
inline auto& define_constant(std::string name, Constant_T value)
{
using Base_T = detail::remove_cv_recursive_t<Constant_T>;
detail::protect(rb_define_const, this->value(), name.c_str(), detail::To_Ruby<Base_T>().convert(value));
detail::protect(rb_define_const, this->validated_value(), name.c_str(), detail::To_Ruby<Base_T>().convert(value));
return *this;
}
4 changes: 4 additions & 0 deletions rice/detail/Parameter.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ namespace Rice::detail
T defaultValue = this->arg()->template defaultValue<T>();
return this->toRuby_.convert(defaultValue);
}
else
{
throw std::runtime_error("Default value not allowed for parameter " + this->arg()->name);
}
}
else
{
Expand Down
14 changes: 2 additions & 12 deletions test/test_Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,7 @@ TESTCASE(implicit_conversion_to_value)
ASSERT_EQUAL(INT2NUM(42), (VALUE)Object(INT2NUM(42)));
ASSERT_EQUAL(Qfalse, (VALUE)Object(Qfalse));
ASSERT_EQUAL(Qundef, (VALUE)Object(Qundef));

ASSERT_EXCEPTION_CHECK(
std::runtime_error,
(VALUE)Object(Qnil),
ASSERT_EQUAL("Rice Object does not wrap a Ruby object", ex.what())
);
ASSERT_EQUAL(Qnil, (VALUE)Object(Qnil));
}

TESTCASE(explicit_conversion_to_value)
Expand All @@ -111,12 +106,7 @@ TESTCASE(explicit_conversion_to_value)
ASSERT_EQUAL(INT2NUM(42), Object(INT2NUM(42)).value());
ASSERT_EQUAL(Qfalse, Object(Qfalse).value());
ASSERT_EQUAL(Qundef, Object(Qundef).value());

ASSERT_EXCEPTION_CHECK(
std::runtime_error,
Object(Qnil).value(),
ASSERT_EQUAL("Rice Object does not wrap a Ruby object", ex.what())
);
ASSERT_EQUAL(Qnil, Object(Qnil).value());
}

TESTCASE(class_of)
Expand Down