Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added tests

  • Loading branch information...
commit 2fd7af9585a371a17a8adba5d85775f9e68f7398 1 parent 8f6bf30
Peter Ohler authored
View
148 ext/oj/cache.c
@@ -0,0 +1,148 @@
+/* cache.c
+ * Copyright (c) 2011, Peter Ohler
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "cache.h"
+
+struct _Cache {
+ char *key; // only set if the node has a value, and it is not an exact match
+ VALUE value;
+ struct _Cache *slots[16];
+};
+
+static void slot_print(Cache cache, unsigned int depth);
+
+void
+oj_cache_new(Cache *cache) {
+ if (0 == (*cache = (Cache)malloc(sizeof(struct _Cache)))) {
+ rb_raise(rb_eNoMemError, "not enough memory\n");
+ }
+ (*cache)->key = 0;
+ (*cache)->value = Qundef;
+ bzero((*cache)->slots, sizeof((*cache)->slots));
+}
+
+VALUE
+oj_cache_get(Cache cache, const char *key, VALUE **slot) {
+ unsigned char *k = (unsigned char*)key;
+ Cache *cp;
+
+ for (; '\0' != *k; k++) {
+ cp = cache->slots + (unsigned int)(*k >> 4); // upper 4 bits
+ if (0 == *cp) {
+ oj_cache_new(cp);
+ }
+ cache = *cp;
+ cp = cache->slots + (unsigned int)(*k & 0x0F); // lower 4 bits
+ if (0 == *cp) {
+ oj_cache_new(cp);
+ cache = *cp;
+ cache->key = ('\0' == *(k + 1)) ? 0 : strdup(key);
+ break;
+ } else {
+ cache = *cp;
+ if (Qundef != cache->value && 0 != cache->key) {
+ unsigned char *ck = (unsigned char*)(cache->key + (unsigned int)(k - (unsigned char*)key + 1));
+
+ if (0 == strcmp((char*)ck, (char*)(k + 1))) {
+ break;
+ } else {
+ Cache *cp2 = cp;
+
+ // if value was set along with the key then there are no slots filled yet
+ cp2 = (*cp2)->slots + (*ck >> 4);
+ oj_cache_new(cp2);
+ cp2 = (*cp2)->slots + (*ck & 0x0F);
+ oj_cache_new(cp2);
+ if ('\0' == *(ck + 1)) {
+ free(cache->key);
+ } else {
+ (*cp2)->key = cache->key;
+ }
+ (*cp2)->value = cache->value;
+ cache->key = 0;
+ cache->value = Qundef;
+ }
+ }
+ }
+ }
+ *slot = &cache->value;
+
+ return cache->value;
+}
+
+void
+oj_cache_print(Cache cache) {
+ //printf("-------------------------------------------\n");
+ slot_print(cache, 0);
+}
+
+static void
+slot_print(Cache c, unsigned int depth) {
+ char indent[256];
+ Cache *cp;
+ unsigned int i;
+
+ if (sizeof(indent) - 1 < depth) {
+ depth = ((int)sizeof(indent) - 1);
+ }
+ memset(indent, ' ', depth);
+ indent[depth] = '\0';
+ for (i = 0, cp = c->slots; i < 16; i++, cp++) {
+ if (0 == *cp) {
+ //printf("%s%02u:\n", indent, i);
+ } else {
+ if (0 == (*cp)->key && Qundef == (*cp)->value) {
+ printf("%s%02u:\n", indent, i);
+ } else {
+ const char *key = (0 == (*cp)->key) ? "*" : (*cp)->key;
+ const char *vs;
+ const char *clas;
+
+ if (Qundef == (*cp)->value) {
+ vs = "undefined";
+ clas = "";
+ } else {
+ VALUE rs = rb_funcall2((*cp)->value, rb_intern("to_s"), 0, 0);
+
+ vs = StringValuePtr(rs);
+ clas = rb_class2name(rb_obj_class((*cp)->value));
+ }
+ printf("%s%02u: %s = %s (%s)\n", indent, i, key, vs, clas);
+ }
+ slot_print(*cp, depth + 2);
+ }
+ }
+}
View
44 ext/oj/cache.h
@@ -0,0 +1,44 @@
+/* cache.h
+ * Copyright (c) 2011, Peter Ohler
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OJ_CACHE_H__
+#define __OJ_CACHE_H__
+
+#include "ruby.h"
+
+typedef struct _Cache *Cache;
+
+extern void oj_cache_new(Cache *cache);
+
+extern VALUE oj_cache_get(Cache cache, const char *key, VALUE **slot);
+
+extern void oj_cache_print(Cache cache);
+
+#endif /* __OJ_CACHE_H__ */
View
30 ext/oj/oj.c
@@ -60,6 +60,9 @@ static VALUE null_sym;
static VALUE object_sym;
static VALUE strict_sym;
+Cache oj_class_cache = 0;
+Cache oj_attr_cache = 0;
+
static struct _Options default_options = {
{ '\0' }, // encoding
0, // indent
@@ -312,6 +315,29 @@ dump(int argc, VALUE *argv, VALUE self) {
return rstr;
}
+
+/* call-seq: to_file(file_path, obj, options)
+ *
+ * Dumps an Object to the specified file.
+ * @param [String] file_path file path to write the JSON document to
+ * @param [Object] obj Object to serialize as an JSON document String
+ * @param [Hash] options formating options
+ * @param [Fixnum] :indent format expected
+ * @param [true|false] :circular allow circular references, default: false
+ */
+static VALUE
+to_file(int argc, VALUE *argv, VALUE self) {
+ struct _Options copts = default_options;
+
+ if (3 == argc) {
+ parse_options(argv[2], &copts);
+ }
+ Check_Type(*argv, T_STRING);
+ oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);
+
+ return Qnil;
+}
+
void Init_oj() {
VALUE keep = Qnil;
@@ -324,6 +350,7 @@ void Init_oj() {
rb_define_module_function(Oj, "load", load_str, -1);
rb_define_module_function(Oj, "load_file", load_file, -1);
rb_define_module_function(Oj, "dump", dump, -1);
+ rb_define_module_function(Oj, "to_file", to_file, -1);
oj_instance_variables_id = rb_intern("instance_variables");
oj_to_hash_id = rb_intern("to_hash");
@@ -341,6 +368,9 @@ void Init_oj() {
strict_sym = ID2SYM(rb_intern("strict")); rb_ary_push(keep, strict_sym);
default_options.mode = ObjectMode;
+
+ oj_cache_new(&oj_class_cache);
+ oj_cache_new(&oj_attr_cache);
}
void
View
5 ext/oj/oj.h
@@ -45,6 +45,8 @@ extern "C" {
#include "ruby/encoding.h"
#endif
+#include "cache.h"
+
#ifdef JRUBY
#define NO_RSTRUCT 1
#endif
@@ -96,6 +98,9 @@ extern ID oj_to_json_id;
extern ID oj_tv_sec_id;
extern ID oj_tv_usec_id;
+extern Cache oj_class_cache;
+extern Cache oj_attr_cache;
+
#if defined(__cplusplus)
#if 0
{ /* satisfy cc-mode */
View
24 notes
@@ -6,9 +6,25 @@
- next
- implement load mode
- - objects
- - hash
-
+ - add class and attr cache
+ - test
+ - rename simple.rb to tests.rb
+ - perf_obj
+ - add msgpack
+ - compare all gems, not just one
+ - maybe a matrix - nah
+ - ox oj marshal
+ *ox - 1.1 3.0
+ oj 0.9 - 2.5
+ marshal 0.3 0.3 -
+
+
+ - Perf
+ - for each
+ - title
+ - Proc
+ -
+
- stream
- load
- dump
@@ -23,3 +39,5 @@
- support circular object encoding
+- Monitoring
+
View
91 test/perf.rb
@@ -0,0 +1,91 @@
+
+class Perf
+
+ def initialize()
+ @items = []
+ end
+
+ def add(title, op, &blk)
+ @items << Item.new(title, op, &blk)
+ end
+
+ def run(iter)
+ base = Item.new(nil, nil) { }
+ base.run(iter, 0.0)
+ @items.each do |i|
+ i.run(iter, base.duration)
+ if i.error.nil?
+ puts "#{i.title}.#{i.op} #{iter} times in %0.3f seconds or %0.3f #{i.op}/sec." % [i.duration, iter / i.duration]
+ else
+ puts "***** #{i.title}.#{i.op} failed! #{i.error}"
+ end
+ end
+ summary()
+ end
+
+ def summary()
+ fastest = nil
+ slowest = nil
+ width = 6
+ @items.each do |i|
+ next if i.duration.nil?
+ width = i.title.size if width < i.title.size
+ end
+ iva = @items.clone
+ iva.delete_if { |i| i.duration.nil? }
+ iva.sort_by! { |i| i.duration }
+ puts
+ puts "Summary:"
+ puts "%*s time (secs) rate (ops/sec)" % [width, 'System']
+ puts "#{'-' * width} ----------- --------------"
+ iva.each do |i|
+ if i.duration.nil?
+ else
+ puts "%*s %11.3f %14.3f" % [width, i.title, i.duration, i.rate ]
+ end
+ end
+ puts
+ puts "Comparison Matrix\n(performance factor, 2.0 row is means twice as fast as column)"
+ puts ([' ' * width] + iva.map { |i| "%*s" % [width, i.title] }).join(' ')
+ puts (['-' * width] + iva.map { |i| '-' * width }).join(' ')
+ iva.each do |i|
+ line = ["%*s" % [width, i.title]]
+ iva.each do |o|
+ line << "%*.2f" % [width, o.duration / i.duration]
+ end
+ puts line.join(' ')
+ end
+ puts
+ end
+
+ class Item
+ attr_accessor :title
+ attr_accessor :op
+ attr_accessor :blk
+ attr_accessor :duration
+ attr_accessor :rate
+ attr_accessor :error
+
+ def initialize(title, op, &blk)
+ @title = title
+ @blk = blk
+ @op = op
+ @duration = nil
+ @rate = nil
+ @error = nil
+ end
+
+ def run(iter, base)
+ begin
+ start = Time.now
+ iter.times { @blk.call }
+ @duration = Time.now - start - base
+ @duration = 0.0 if @duration < 0.0
+ @rate = iter / @duration
+ rescue Exception => e
+ @error = "#{e.class}: #{e.message}"
+ end
+ end
+
+ end # Item
+end # Perf
View
206 test/perf_obj.rb
@@ -1,7 +1,6 @@
#!/usr/bin/env ruby -wW1
$: << '.'
-$: << '..'
$: << '../lib'
$: << '../ext'
@@ -15,11 +14,12 @@
require 'optparse'
require 'ox'
require 'oj'
+require 'perf'
require 'sample'
require 'files'
-$verbose = 0
$circular = false
+$indent = 0
do_sample = false
do_files = false
@@ -31,8 +31,6 @@
$iter = 1000
opts = OptionParser.new
-opts.on("-v", "increase verbosity") { $verbose += 1 }
-
opts.on("-c", "circular options") { $circular = true }
opts.on("-s", "load and dump as sample Ruby object") { do_sample = true }
@@ -49,164 +47,78 @@
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
files = opts.parse(ARGV)
+$obj = nil
+$xml = nil
+$mars = nil
+$json = nil
+
+unless do_load || do_dump || do_read || do_write
+ do_load = true
+ do_dump = true
+ do_read = true
+ do_write = true
+end
+
+# prepare all the formats for input
if files.empty?
- data = []
- obj = do_sample ? sample_doc(2) : files('..')
- mars = Marshal.dump(obj)
- xml = Ox.dump(obj, :indent => 0, circular: $circular)
- json = Oj.dump(obj, :indent => 0, circular: $circular)
- File.open('sample.xml', 'w') { |f| f.write(xml) }
- File.open('sample.json', 'w') { |f| f.write(json) }
- File.open('sample.marshal', 'w') { |f| f.write(mars) }
- data << { :file => 'sample.xml', :obj => obj, :xml => xml, :marshal => mars, :json => json }
+ $obj = do_sample ? sample_doc(2) : files('..')
+ $mars = Marshal.dump($obj)
+ $xml = Ox.dump($obj, :indent => $indent, circular: $circular)
+ $json = Oj.dump($obj, :indent => $indent, circular: $circular)
+ File.open('sample.xml', 'w') { |f| f.write($xml) }
+ File.open('sample.json', 'w') { |f| f.write($json) }
+ File.open('sample.marshal', 'w') { |f| f.write($mars) }
else
puts "loading and parsing #{files}\n\n"
# TBD change to allow xml and json
data = files.map do |f|
- xml = File.read(f)
- obj = Ox.load(xml);
- mars = Marshal.dump(obj)
- json = Oj.dump(obj, :indent => 0, circular: $circular)
- { :file => f, :obj => obj, :xml => xml, :marshal => mars, :json => json }
+ $xml = File.read(f)
+ $obj = Ox.load($xml);
+ $mars = Marshal.dump($obj)
+ $json = Oj.dump($obj, :indent => $indent, circular: $circular)
end
end
-$ox_load_time = 0
-$mars_load_time = 0
-$ox_dump_time = 0
-$oj_dump_time = 0
-$mars_dump_time = 0
-
-def perf_load(d)
- filename = d[:file]
- marshal_filename = 'sample.marshal'
- xml = d[:xml]
- mars = d[:marshal]
- json = d[:json]
-
- if 0 < $verbose
- obj = Ox.load(xml, :mode => :object, :trace => $verbose)
- return
- end
- start = Time.now
- (1..$iter).each do
- obj = Ox.load(xml, :mode => :object)
- end
- $ox_load_time = Time.now - start
- puts "Parsing #{$iter} times with Ox took #{$ox_load_time} seconds."
+Oj.default_options = { :mode => :object, :indent => $indent }
- start = Time.now
- (1..$iter).each do
- obj = Oj.load(json, :mode => :object)
- end
- $oj_load_time = Time.now - start
- puts "Parsing #{$iter} times with Oj took #{$oj_load_time} seconds."
-
- start = Time.now
- (1..$iter).each do
- obj = Marshal.load(mars)
- end
- $mars_load_time = Time.now - start
- puts "Marshalling #{$iter} times took #{$mars_load_time} seconds."
- puts ">>> Ox is %0.1f faster than Marshal loading.\n\n" % [$mars_load_time/$ox_load_time]
+if do_load
+ puts '-' * 80
+ puts "Load Performance"
+ perf = Perf.new()
+ perf.add('Ox', 'load') { Ox.load($xml, :mode => :object) }
+ perf.add('Oj', 'load') { Oj.load($json) }
+ perf.add('Marshal', 'load') { Marshal.load($mars) }
+ perf.run($iter)
end
-def perf_dump(d)
- obj = d[:obj]
-
- start = Time.now
- (1..$iter).each do
- xml = Ox.dump(obj, :indent => 2, :circular => $circular)
- #puts "*** ox:\n#{xml}"
- end
- $ox_dump_time = Time.now - start
- puts "Ox dumping #{$iter} times with ox took #{$ox_dump_time} seconds."
-
- Oj.default_options = {:indent => 2}
- start = Time.now
- (1..$iter).each do
- json = Oj.dump(obj)
- end
- $oj_dump_time = Time.now - start
- puts "Oj dumping #{$iter} times with oj took #{$oj_dump_time} seconds."
-
- obj = d[:obj]
- start = Time.now
- (1..$iter).each do
- m = Marshal.dump(obj)
- end
- $mars_dump_time = Time.now - start
- puts "Marshal dumping #{$iter} times took #{$mars_dump_time} seconds."
- puts ">>> Ox is %0.1f faster than Marshal dumping.\n\n" % [$mars_dump_time/$ox_dump_time]
+if do_dump
+ puts '-' * 80
+ puts "Dump Performance"
+ perf = Perf.new()
+ perf.add('Ox', 'dump') { Ox.dump($obj, :indent => $indent, :circular => $circular) }
+ perf.add('Oj', 'dump') { Oj.dump($obj) }
+ perf.add('Marshal', 'dump') { Marshal.dump($obj) }
+ perf.run($iter)
end
-def perf_read(d)
- ox_read_time = 0
- mars_read_time = 0
-
- filename = d[:file]
- marshal_filename = 'sample.marshal'
- xml = d[:xml]
- mars = d[:marshal]
-
- # now load from the file
- start = Time.now
- (1..$iter).each do
- obj = Ox.load_file(filename, :mode => :object)
- end
- ox_read_time = Time.now - start
- puts "Loading and parsing #{$iter} times with ox took #{ox_read_time} seconds."
-
- start = Time.now
- (1..$iter).each do
- m = File.read(marshal_filename)
- obj = Marshal.load(m)
- end
- mars_read_time = Time.now - start
- puts "Reading and marshalling #{$iter} times took #{mars_read_time} seconds."
- puts ">>> Ox is %0.1f faster than Marshal loading and parsing.\n\n" % [mars_read_time/ox_read_time]
-
+if do_read
+ puts '-' * 80
+ puts "Read from file Performance"
+ perf = Perf.new()
+ perf.add('Ox', 'load_file') { Ox.load_file('sample.xml', :mode => :object) }
+ perf.add('Oj', 'load') { Oj.load_file('sample.json') }
+ perf.add('Marshal', 'load') { Marshal.load(File.new('sample.marshal')) }
+ perf.run($iter)
end
-def perf_write(d)
- ox_write_time = 0
- mars_write_time = 0
-
- ox_filename = 'out.xml'
- marshal_filename = 'out.marshal'
- obj = d[:obj]
-
- start = Time.now
- (1..$iter).each do
- xml = Ox.to_file(ox_filename, obj, :indent => 0)
- end
- ox_write_time = Time.now - start
- puts "Ox dumping #{$iter} times with ox took #{ox_write_time} seconds."
-
- start = Time.now
- (1..$iter).each do
- m = Marshal.dump(obj, circular: $circular)
- File.open(marshal_filename, "w") { |f| f.write(m) }
- end
- mars_write_time = Time.now - start
- puts "Marshal dumping and writing #{$iter} times took #{mars_write_time} seconds."
- puts ">>> Ox is %0.1f faster than Marshal dumping.\n\n" % [mars_write_time/ox_write_time]
-
+if do_write
+ puts '-' * 80
+ puts "Write to file Performance"
+ perf = Perf.new()
+ perf.add('Ox', 'to_file') { Ox.to_file('sample.xml', $obj, :indent => $indent, :circular => $circular) }
+ perf.add('Oj', 'to_file') { Oj.to_file('sample.json', $obj) }
+ perf.add('Marshal', 'dump') { Marshal.dump($obj, File.new('sample.marshal', 'w')) }
+ perf.run($iter)
end
-#if do_sample or do_files
- data.each do |d|
- puts "Using file #{d[:file]}."
-
- perf_load(d) if do_load
- perf_dump(d) if do_dump
- if do_load and do_dump
- puts ">>> Ox is %0.1f faster than Marshal dumping and loading.\n\n" % [($mars_load_time + $mars_dump_time)/($ox_load_time + $ox_dump_time)] unless 0 == $mars_load_time
- end
-
- perf_read(d) if do_read
- perf_write(d) if do_write
-
- end
-#end
View
39 test/sample/file.rb
@@ -14,17 +14,34 @@ def initialize(filename)
@size = stat.size
@owner = Etc.getpwuid(stat.uid).name
@group = Etc.getgrgid(stat.gid).name
- @permissions = {
- :user => [(0 != (stat.mode & 0x0100)) ? 'r' : '-',
- (0 != (stat.mode & 0x0080)) ? 'w' : '-',
- (0 != (stat.mode & 0x0040)) ? 'x' : '-'].join(''),
- :group => [(0 != (stat.mode & 0x0020)) ? 'r' : '-',
- (0 != (stat.mode & 0x0010)) ? 'w' : '-',
- (0 != (stat.mode & 0x0008)) ? 'x' : '-'].join(''),
- :other => [(0 != (stat.mode & 0x0004)) ? 'r' : '-',
- (0 != (stat.mode & 0x0002)) ? 'w' : '-',
- (0 != (stat.mode & 0x0001)) ? 'x' : '-'].join('')
- }
+ if false
+ @permissions = {
+ 'user' => {
+ 'read' => (0 != (stat.mode & 0x0100)),
+ 'write' => (0 != (stat.mode & 0x0080)),
+ 'execute' => (0 != (stat.mode & 0x0040))},
+ 'group' => {
+ 'read' => (0 != (stat.mode & 0x0020)),
+ 'write' => (0 != (stat.mode & 0x0010)),
+ 'execute' => (0 != (stat.mode & 0x0008))},
+ 'other' => {
+ 'read' => (0 != (stat.mode & 0x0004)),
+ 'write' => (0 != (stat.mode & 0x0002)),
+ 'execute' => (0 != (stat.mode & 0x0001))}
+ }
+ else
+ @permissions = {
+ 'user' => [(0 != (stat.mode & 0x0100)) ? 'r' : '-',
+ (0 != (stat.mode & 0x0080)) ? 'w' : '-',
+ (0 != (stat.mode & 0x0040)) ? 'x' : '-'].join(''),
+ 'group' => [(0 != (stat.mode & 0x0020)) ? 'r' : '-',
+ (0 != (stat.mode & 0x0010)) ? 'w' : '-',
+ (0 != (stat.mode & 0x0008)) ? 'x' : '-'].join(''),
+ 'other' => [(0 != (stat.mode & 0x0004)) ? 'r' : '-',
+ (0 != (stat.mode & 0x0002)) ? 'w' : '-',
+ (0 != (stat.mode & 0x0001)) ? 'x' : '-'].join('')
+ }
+ end
end
end # File
Please sign in to comment.
Something went wrong with that request. Please try again.