class Cmpi::CMPIInstance
Class instance (object)
Attributes
typemap[RW]
Public Instance Methods
each() { |get_property_at| ... }
click to toggle source
# File cmpi.rb, line 425 def each (0..size-1).each do |i| yield self.get_property_at(i) end end
get(p1)
click to toggle source
get a named property value Property access in Ruby: data = instance # access by name (symbol) data = instance # access by name (string) data = instance # access by index
See #get_property_at to retrieve property name and value
VALUE get(VALUE property) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIData data; if (FIXNUM_P(property)) { data = CMGetPropertyAt($self, FIX2ULONG(property), NULL, &st); } else { const char *name; name = target_charptr(property); data = CMGetProperty($self, name, &st); } RAISE_IF(st); return data_value(&data); } #if defined (SWIGRUBY) VALUE #endif #if defined (SWIGPYTHON) PyObject* #endif #if defined (SWIGPERL) SV * #endif /** Gets a Property name and value defined by its index. * index: Position in the internal Data array. */ __type get_property_at(int index) { Target_Type tdata; Target_Type result; CMPIString *s = NULL; CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIData data = CMGetPropertyAt($self, index, &s, &st); if (st.rc) { RAISE_IF(st); result = Target_Null; Target_INCREF(result); return result; } /* fprintf(stderr, "CMGetPropertyAt(%d) -> name %s, data type %x, state %x, value %p\n", index, CMGetCharPtr(s), data.type, data.state, data.value); fflush(stderr); */ TARGET_THREAD_BEGIN_BLOCK; tdata = data_data(&data); #if defined (SWIGPYTHON) result = PyTuple_New(2); PyTuple_SetItem(result, 0, tdata); PyTuple_SetItem(result, 1, PyString_FromString(CMGetCharPtr(s))); #else result = Target_SizedArray(2); Target_Append(result, tdata); Target_Append(result, Target_String(CMGetCharPtr(s))); #endif TARGET_THREAD_END_BLOCK; CMRelease(s); return result; } %alias property_count "size"; /* Gets the number of properties contained in this Instance. */ int property_count() { int result; CMPIStatus st = { CMPI_RC_OK, NULL }; result = CMGetPropertyCount($self, &st); RAISE_IF(st); return result; } /* Generates an ObjectPath out of the namespace, classname and * key propeties of this Instance. */ CMPIObjectPath *objectpath() { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* result; result = CMGetObjectPath($self, &st); RAISE_IF(st); /* fprintf(stderr, "<%p>.objectpath = %p\n", $self, result); */ return result; } %alias set_objectpath "objectpath="; /* Replaces the ObjectPath of the instance. * The passed objectpath shall contain the namespace, classname, * as well as all keys for the specified instance. */ void set_objectpath(const CMPIObjectPath *path) { RAISE_IF(CMSetObjectPath($self, path)); } /* Directs CMPI to ignore any setProperty operations for this * instance for any properties not in this list. * properties: If not NULL, the members of the array define one * or more Property names to be accepted by setProperty operations. */ void set_property_filter(const char **properties) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* cop; CMPICount n; CMPICount i; char** props; /* Make copy of property list (we may modify it) */ props = string_array_clone((char**)properties); #if 0 string_array_print(props); #endif /* Pegasus requires that the keys be in the property list, else it * throws an exception. To work around, add key properties to property * list. */ if (!(cop = CMGetObjectPath($self, &st)) || st.rc) { st.rc = CMPI_RC_ERR_FAILED; RAISE_IF(st); string_array_free(props); return; } n = CMGetKeyCount(cop, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } for (i = 0; i < n; i++) { CMPIString* pn = NULL; const char* str; (void)CMGetKeyAt(cop, i, &pn, &st); /* get key name at i */ if (st.rc) { RAISE_IF(st); string_array_free(props); return; } str = CMGetCharsPtr(pn, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } if (string_array_find_ignore_case(props, str) == NULL) props = string_array_append(props, str); } #if 0 string_array_print(props); #endif RAISE_IF(CMSetPropertyFilter($self, (const char**)props, NULL)); string_array_free(props); } /* Add/replace a named Property value and origin * name: is a string containing the Property name. * value: points to a CMPIValue structure containing the value * to be assigned to the Property. * type: is a CMPIType structure defining the type of the value. * origin: specifies the instance origin. If NULL, then no origin is attached to the property */ void set_property_with_origin( const char *name, const CMPIValue *value, CMPIType type, const char* origin) { RAISE_IF(CMSetPropertyWithOrigin($self, name, value, type, origin)); } }
get_property_at(p1)
click to toggle source
Gets a Property name and value defined by its index.
index: Position in the internal Data array.
__type get_property_at(int index) { Target_Type tdata; Target_Type result; CMPIString *s = NULL; CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIData data = CMGetPropertyAt($self, index, &s, &st); if (st.rc) { RAISE_IF(st); result = Target_Null; Target_INCREF(result); return result; } /* fprintf(stderr, "CMGetPropertyAt(%d) -> name %s, data type %x, state %x, value %p\n", index, CMGetCharPtr(s), data.type, data.state, data.value); fflush(stderr); */ TARGET_THREAD_BEGIN_BLOCK; tdata = data_data(&data); #if defined (SWIGPYTHON) result = PyTuple_New(2); PyTuple_SetItem(result, 0, tdata); PyTuple_SetItem(result, 1, PyString_FromString(CMGetCharPtr(s))); #else result = Target_SizedArray(2); Target_Append(result, tdata); Target_Append(result, Target_String(CMGetCharPtr(s))); #endif TARGET_THREAD_END_BLOCK; CMRelease(s); return result; } %alias property_count "size"; /* Gets the number of properties contained in this Instance. */ int property_count() { int result; CMPIStatus st = { CMPI_RC_OK, NULL }; result = CMGetPropertyCount($self, &st); RAISE_IF(st); return result; } /* Generates an ObjectPath out of the namespace, classname and * key propeties of this Instance. */ CMPIObjectPath *objectpath() { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* result; result = CMGetObjectPath($self, &st); RAISE_IF(st); /* fprintf(stderr, "<%p>.objectpath = %p\n", $self, result); */ return result; } %alias set_objectpath "objectpath="; /* Replaces the ObjectPath of the instance. * The passed objectpath shall contain the namespace, classname, * as well as all keys for the specified instance. */ void set_objectpath(const CMPIObjectPath *path) { RAISE_IF(CMSetObjectPath($self, path)); } /* Directs CMPI to ignore any setProperty operations for this * instance for any properties not in this list. * properties: If not NULL, the members of the array define one * or more Property names to be accepted by setProperty operations. */ void set_property_filter(const char **properties) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* cop; CMPICount n; CMPICount i; char** props; /* Make copy of property list (we may modify it) */ props = string_array_clone((char**)properties); #if 0 string_array_print(props); #endif /* Pegasus requires that the keys be in the property list, else it * throws an exception. To work around, add key properties to property * list. */ if (!(cop = CMGetObjectPath($self, &st)) || st.rc) { st.rc = CMPI_RC_ERR_FAILED; RAISE_IF(st); string_array_free(props); return; } n = CMGetKeyCount(cop, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } for (i = 0; i < n; i++) { CMPIString* pn = NULL; const char* str; (void)CMGetKeyAt(cop, i, &pn, &st); /* get key name at i */ if (st.rc) { RAISE_IF(st); string_array_free(props); return; } str = CMGetCharsPtr(pn, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } if (string_array_find_ignore_case(props, str) == NULL) props = string_array_append(props, str); } #if 0 string_array_print(props); #endif RAISE_IF(CMSetPropertyFilter($self, (const char**)props, NULL)); string_array_free(props); } /* Add/replace a named Property value and origin * name: is a string containing the Property name. * value: points to a CMPIValue structure containing the value * to be assigned to the Property. * type: is a CMPIType structure defining the type of the value. * origin: specifies the instance origin. If NULL, then no origin is attached to the property */ void set_property_with_origin( const char *name, const CMPIValue *value, CMPIType type, const char* origin) { RAISE_IF(CMSetPropertyWithOrigin($self, name, value, type, origin)); } }
method_missing(name, *args)
click to toggle source
Allow Instance.Property and Instance.Property=
# File cmpi.rb, line 451 def method_missing name, *args s = name.to_s if s =~ /=$/ v = args[0] n = s.chop # -> http://blog.sidu.in/2008/02/loading-classes-from-strings-in-ruby.html unless @typemap begin @typemap = Cmpi.const_get(self.objectpath.classname).typemap rescue NoMethodError raise RCErrInvalidClass.new(CMPI_RC_ERR_INVALID_CLASS, "Cmpi::#{self.objectpath.classname}.typemap not defined") end end t = @typemap[n] raise RCErrNotFound.new(CMPI_RC_ERR_NOT_FOUND, "Property '#{n}' of Cmpi::#{self.objectpath.classname}.typemap not defined") unless t STDERR.printf "Instance.%s = %s[%s]:%04x\n" % [n, v, v.class, t] self[n,v] = t else # STDERR.puts "CMPIInstance.#{name} -> #{self[s].inspect}" self[s] end end
objectpath()
click to toggle source
Generates an ObjectPath out of the namespace, classname and
key propeties of this Instance.
CMPIObjectPath *objectpath() { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* result; result = CMGetObjectPath($self, &st); RAISE_IF(st); /* fprintf(stderr, "<%p>.objectpath = %p\n", $self, result); */ return result; } %alias set_objectpath "objectpath="; /* Replaces the ObjectPath of the instance. * The passed objectpath shall contain the namespace, classname, * as well as all keys for the specified instance. */ void set_objectpath(const CMPIObjectPath *path) { RAISE_IF(CMSetObjectPath($self, path)); } /* Directs CMPI to ignore any setProperty operations for this * instance for any properties not in this list. * properties: If not NULL, the members of the array define one * or more Property names to be accepted by setProperty operations. */ void set_property_filter(const char **properties) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* cop; CMPICount n; CMPICount i; char** props; /* Make copy of property list (we may modify it) */ props = string_array_clone((char**)properties); #if 0 string_array_print(props); #endif /* Pegasus requires that the keys be in the property list, else it * throws an exception. To work around, add key properties to property * list. */ if (!(cop = CMGetObjectPath($self, &st)) || st.rc) { st.rc = CMPI_RC_ERR_FAILED; RAISE_IF(st); string_array_free(props); return; } n = CMGetKeyCount(cop, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } for (i = 0; i < n; i++) { CMPIString* pn = NULL; const char* str; (void)CMGetKeyAt(cop, i, &pn, &st); /* get key name at i */ if (st.rc) { RAISE_IF(st); string_array_free(props); return; } str = CMGetCharsPtr(pn, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } if (string_array_find_ignore_case(props, str) == NULL) props = string_array_append(props, str); } #if 0 string_array_print(props); #endif RAISE_IF(CMSetPropertyFilter($self, (const char**)props, NULL)); string_array_free(props); } /* Add/replace a named Property value and origin * name: is a string containing the Property name. * value: points to a CMPIValue structure containing the value * to be assigned to the Property. * type: is a CMPIType structure defining the type of the value. * origin: specifies the instance origin. If NULL, then no origin is attached to the property */ void set_property_with_origin( const char *name, const CMPIValue *value, CMPIType type, const char* origin) { RAISE_IF(CMSetPropertyWithOrigin($self, name, value, type, origin)); } }
property_count()
click to toggle source
Gets the number of properties contained in this Instance.
int property_count() { int result; CMPIStatus st = { CMPI_RC_OK, NULL }; result = CMGetPropertyCount($self, &st); RAISE_IF(st); return result; } /* Generates an ObjectPath out of the namespace, classname and * key propeties of this Instance. */ CMPIObjectPath *objectpath() { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* result; result = CMGetObjectPath($self, &st); RAISE_IF(st); /* fprintf(stderr, "<%p>.objectpath = %p\n", $self, result); */ return result; } %alias set_objectpath "objectpath="; /* Replaces the ObjectPath of the instance. * The passed objectpath shall contain the namespace, classname, * as well as all keys for the specified instance. */ void set_objectpath(const CMPIObjectPath *path) { RAISE_IF(CMSetObjectPath($self, path)); } /* Directs CMPI to ignore any setProperty operations for this * instance for any properties not in this list. * properties: If not NULL, the members of the array define one * or more Property names to be accepted by setProperty operations. */ void set_property_filter(const char **properties) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* cop; CMPICount n; CMPICount i; char** props; /* Make copy of property list (we may modify it) */ props = string_array_clone((char**)properties); #if 0 string_array_print(props); #endif /* Pegasus requires that the keys be in the property list, else it * throws an exception. To work around, add key properties to property * list. */ if (!(cop = CMGetObjectPath($self, &st)) || st.rc) { st.rc = CMPI_RC_ERR_FAILED; RAISE_IF(st); string_array_free(props); return; } n = CMGetKeyCount(cop, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } for (i = 0; i < n; i++) { CMPIString* pn = NULL; const char* str; (void)CMGetKeyAt(cop, i, &pn, &st); /* get key name at i */ if (st.rc) { RAISE_IF(st); string_array_free(props); return; } str = CMGetCharsPtr(pn, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } if (string_array_find_ignore_case(props, str) == NULL) props = string_array_append(props, str); } #if 0 string_array_print(props); #endif RAISE_IF(CMSetPropertyFilter($self, (const char**)props, NULL)); string_array_free(props); } /* Add/replace a named Property value and origin * name: is a string containing the Property name. * value: points to a CMPIValue structure containing the value * to be assigned to the Property. * type: is a CMPIType structure defining the type of the value. * origin: specifies the instance origin. If NULL, then no origin is attached to the property */ void set_property_with_origin( const char *name, const CMPIValue *value, CMPIType type, const char* origin) { RAISE_IF(CMSetPropertyWithOrigin($self, name, value, type, origin)); } }
set_objectpath(p1)
click to toggle source
Replaces the ObjectPath of the instance.
The passed objectpath shall contain the namespace, classname, as well as all keys for the specified instance.
void set_objectpath(const CMPIObjectPath *path) { RAISE_IF(CMSetObjectPath($self, path)); } /* Directs CMPI to ignore any setProperty operations for this * instance for any properties not in this list. * properties: If not NULL, the members of the array define one * or more Property names to be accepted by setProperty operations. */ void set_property_filter(const char **properties) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* cop; CMPICount n; CMPICount i; char** props; /* Make copy of property list (we may modify it) */ props = string_array_clone((char**)properties); #if 0 string_array_print(props); #endif /* Pegasus requires that the keys be in the property list, else it * throws an exception. To work around, add key properties to property * list. */ if (!(cop = CMGetObjectPath($self, &st)) || st.rc) { st.rc = CMPI_RC_ERR_FAILED; RAISE_IF(st); string_array_free(props); return; } n = CMGetKeyCount(cop, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } for (i = 0; i < n; i++) { CMPIString* pn = NULL; const char* str; (void)CMGetKeyAt(cop, i, &pn, &st); /* get key name at i */ if (st.rc) { RAISE_IF(st); string_array_free(props); return; } str = CMGetCharsPtr(pn, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } if (string_array_find_ignore_case(props, str) == NULL) props = string_array_append(props, str); } #if 0 string_array_print(props); #endif RAISE_IF(CMSetPropertyFilter($self, (const char**)props, NULL)); string_array_free(props); } /* Add/replace a named Property value and origin * name: is a string containing the Property name. * value: points to a CMPIValue structure containing the value * to be assigned to the Property. * type: is a CMPIType structure defining the type of the value. * origin: specifies the instance origin. If NULL, then no origin is attached to the property */ void set_property_with_origin( const char *name, const CMPIValue *value, CMPIType type, const char* origin) { RAISE_IF(CMSetPropertyWithOrigin($self, name, value, type, origin)); } }
set_property(p1, p2, p3)
click to toggle source
Adds/replaces a named Property.
name: Entry name. value: Address of value structure. type: Value type.
void set_property( const char *name, const CMPIValue * value, const CMPIType type) { RAISE_IF(CMSetProperty($self, name, value, type)); } %alias get "[]"; /* * get a named property value * Property access in Ruby: * data = instance[:propname] # access by name (symbol) * data = instance["propname"] # access by name (string) * data = instance[1] # access by index * * See get_property_at to retrieve property name and value */ VALUE get(VALUE property) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIData data; if (FIXNUM_P(property)) { data = CMGetPropertyAt($self, FIX2ULONG(property), NULL, &st); } else { const char *name; name = target_charptr(property); data = CMGetProperty($self, name, &st); } RAISE_IF(st); return data_value(&data); } #if defined (SWIGRUBY) VALUE #endif #if defined (SWIGPYTHON) PyObject* #endif #if defined (SWIGPERL) SV * #endif /** Gets a Property name and value defined by its index. * index: Position in the internal Data array. */ __type get_property_at(int index) { Target_Type tdata; Target_Type result; CMPIString *s = NULL; CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIData data = CMGetPropertyAt($self, index, &s, &st); if (st.rc) { RAISE_IF(st); result = Target_Null; Target_INCREF(result); return result; } /* fprintf(stderr, "CMGetPropertyAt(%d) -> name %s, data type %x, state %x, value %p\n", index, CMGetCharPtr(s), data.type, data.state, data.value); fflush(stderr); */ TARGET_THREAD_BEGIN_BLOCK; tdata = data_data(&data); #if defined (SWIGPYTHON) result = PyTuple_New(2); PyTuple_SetItem(result, 0, tdata); PyTuple_SetItem(result, 1, PyString_FromString(CMGetCharPtr(s))); #else result = Target_SizedArray(2); Target_Append(result, tdata); Target_Append(result, Target_String(CMGetCharPtr(s))); #endif TARGET_THREAD_END_BLOCK; CMRelease(s); return result; } %alias property_count "size"; /* Gets the number of properties contained in this Instance. */ int property_count() { int result; CMPIStatus st = { CMPI_RC_OK, NULL }; result = CMGetPropertyCount($self, &st); RAISE_IF(st); return result; } /* Generates an ObjectPath out of the namespace, classname and * key propeties of this Instance. */ CMPIObjectPath *objectpath() { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* result; result = CMGetObjectPath($self, &st); RAISE_IF(st); /* fprintf(stderr, "<%p>.objectpath = %p\n", $self, result); */ return result; } %alias set_objectpath "objectpath="; /* Replaces the ObjectPath of the instance. * The passed objectpath shall contain the namespace, classname, * as well as all keys for the specified instance. */ void set_objectpath(const CMPIObjectPath *path) { RAISE_IF(CMSetObjectPath($self, path)); } /* Directs CMPI to ignore any setProperty operations for this * instance for any properties not in this list. * properties: If not NULL, the members of the array define one * or more Property names to be accepted by setProperty operations. */ void set_property_filter(const char **properties) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* cop; CMPICount n; CMPICount i; char** props; /* Make copy of property list (we may modify it) */ props = string_array_clone((char**)properties); #if 0 string_array_print(props); #endif /* Pegasus requires that the keys be in the property list, else it * throws an exception. To work around, add key properties to property * list. */ if (!(cop = CMGetObjectPath($self, &st)) || st.rc) { st.rc = CMPI_RC_ERR_FAILED; RAISE_IF(st); string_array_free(props); return; } n = CMGetKeyCount(cop, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } for (i = 0; i < n; i++) { CMPIString* pn = NULL; const char* str; (void)CMGetKeyAt(cop, i, &pn, &st); /* get key name at i */ if (st.rc) { RAISE_IF(st); string_array_free(props); return; } str = CMGetCharsPtr(pn, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } if (string_array_find_ignore_case(props, str) == NULL) props = string_array_append(props, str); } #if 0 string_array_print(props); #endif RAISE_IF(CMSetPropertyFilter($self, (const char**)props, NULL)); string_array_free(props); } /* Add/replace a named Property value and origin * name: is a string containing the Property name. * value: points to a CMPIValue structure containing the value * to be assigned to the Property. * type: is a CMPIType structure defining the type of the value. * origin: specifies the instance origin. If NULL, then no origin is attached to the property */ void set_property_with_origin( const char *name, const CMPIValue *value, CMPIType type, const char* origin) { RAISE_IF(CMSetPropertyWithOrigin($self, name, value, type, origin)); } }
set_property_filter(p1)
click to toggle source
Directs CMPI to ignore any setProperty operations for this
instance for any properties not in this list. properties: If not NULL, the members of the array define one or more Property names to be accepted by setProperty operations.
void set_property_filter(const char **properties) { CMPIStatus st = { CMPI_RC_OK, NULL }; CMPIObjectPath* cop; CMPICount n; CMPICount i; char** props; /* Make copy of property list (we may modify it) */ props = string_array_clone((char**)properties); #if 0 string_array_print(props); #endif /* Pegasus requires that the keys be in the property list, else it * throws an exception. To work around, add key properties to property * list. */ if (!(cop = CMGetObjectPath($self, &st)) || st.rc) { st.rc = CMPI_RC_ERR_FAILED; RAISE_IF(st); string_array_free(props); return; } n = CMGetKeyCount(cop, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } for (i = 0; i < n; i++) { CMPIString* pn = NULL; const char* str; (void)CMGetKeyAt(cop, i, &pn, &st); /* get key name at i */ if (st.rc) { RAISE_IF(st); string_array_free(props); return; } str = CMGetCharsPtr(pn, &st); if (st.rc) { RAISE_IF(st); string_array_free(props); return; } if (string_array_find_ignore_case(props, str) == NULL) props = string_array_append(props, str); } #if 0 string_array_print(props); #endif RAISE_IF(CMSetPropertyFilter($self, (const char**)props, NULL)); string_array_free(props); } /* Add/replace a named Property value and origin * name: is a string containing the Property name. * value: points to a CMPIValue structure containing the value * to be assigned to the Property. * type: is a CMPIType structure defining the type of the value. * origin: specifies the instance origin. If NULL, then no origin is attached to the property */ void set_property_with_origin( const char *name, const CMPIValue *value, CMPIType type, const char* origin) { RAISE_IF(CMSetPropertyWithOrigin($self, name, value, type, origin)); } }
set_property_with_origin(p1, p2, p3, p4)
click to toggle source
Add/replace a named Property value and origin
name: is a string containing the Property name. value: points to a CMPIValue structure containing the value to be assigned to the Property. type: is a CMPIType structure defining the type of the value. origin: specifies the instance origin. If NULL, then no origin is attached to the property
void set_property_with_origin( const char *name, const CMPIValue *value, CMPIType type, const char* origin) { RAISE_IF(CMSetPropertyWithOrigin($self, name, value, type, origin)); } }
to_s()
click to toggle source
# File cmpi.rb, line 430 def to_s # objectpath only covers the key properties path = objectpath keys = [] path.each { |val,name| keys << name } # now iterate over the instance properties, filter # out the key properties from the objectpath # and collect the non-key properties s = "" self.each do |value,name| next unless value next if keys.include? name s << ", " unless s.empty? s << "\"#{name}\"=#{value.inspect}" end # path has the key properties, s has the non-key properties "#{path} #{s}" end