├── VERSION ├── var ├── name ├── title ├── created ├── organization ├── summary ├── copyrights ├── requirements ├── authors └── repositories ├── lib ├── carats.rb └── carats │ ├── hash │ └── rekey.rb │ ├── string │ └── splice.rb │ └── kernel │ └── identical.rb ├── .gitignore ├── task └── assembly.rb ├── site ├── assets │ ├── fork-me.png │ └── images │ │ └── carrot.jpg └── index.html ├── NOTICE.md ├── ext ├── hash │ ├── rekey │ │ ├── extconf.rb │ │ ├── hash_rekey.c │ │ ├── README.md │ │ └── rekey.rb │ ├── op_push │ │ ├── extconf.rb │ │ ├── op_push.rb │ │ ├── README.md │ │ └── hash_op_push.c │ └── slice │ │ ├── README.md │ │ └── slice.rb ├── basicobject │ ├── extconf.rb │ ├── README.md │ └── basicobject.c ├── array │ ├── each_pair │ │ ├── extconf.rb │ │ ├── each_pair.rb │ │ ├── README.md │ │ └── array_each_pair.c │ └── each_value │ │ ├── extconf.rb │ │ ├── each_value.rb │ │ ├── array_each_value.c │ │ └── README.md ├── string │ ├── splice │ │ ├── extconf.rb │ │ ├── README.md │ │ ├── splice.rb │ │ └── string_splice.c │ ├── margin │ │ ├── README.md │ │ └── margin.rb │ └── indent │ │ ├── string_indent.c │ │ ├── README.md │ │ └── indent.rb ├── kernel │ ├── identical │ │ ├── extconf.rb │ │ ├── identical.rb │ │ ├── README.md │ │ └── kernel_identical.c │ ├── required │ │ ├── extconf.rb │ │ ├── README.md │ │ └── kernel_required.c │ ├── truefalse │ │ ├── extconf.rb │ │ ├── kernel_truefalse.c │ │ ├── README.md │ │ └── truefalse.rb │ └── require_path │ │ ├── extconf.rb │ │ ├── README.md │ │ └── kernel_require_path.c ├── module │ ├── anonymous │ │ ├── extconf.rb │ │ ├── README.md │ │ ├── anonymous.rb │ │ └── module_anonymous.c │ └── is │ │ ├── README.md │ │ └── module_is.c └── null │ ├── extconf.rb │ ├── null.c │ └── README.md ├── work ├── step │ ├── lib │ │ ├── step │ │ │ ├── itimer.h │ │ │ ├── filesys.h │ │ │ ├── itimer.c │ │ │ └── filesys.c │ │ ├── mkrf_conf │ │ ├── Rakefile │ │ ├── step.h │ │ └── step.c │ ├── README │ ├── LICENSE │ └── step.gemspec ├── prelude.rb.yaml.patch ├── name.patch └── parse.y.yaml.patch ├── Rakefile ├── .index ├── README.md ├── .gemspec └── LICENCE.txt /VERSION: -------------------------------------------------------------------------------- 1 | 0.4.0 2 | -------------------------------------------------------------------------------- /var/name: -------------------------------------------------------------------------------- 1 | carats 2 | -------------------------------------------------------------------------------- /var/title: -------------------------------------------------------------------------------- 1 | Carats 2 | -------------------------------------------------------------------------------- /var/created: -------------------------------------------------------------------------------- 1 | 2004-09-01 2 | -------------------------------------------------------------------------------- /var/organization: -------------------------------------------------------------------------------- 1 | Rubyworks 2 | -------------------------------------------------------------------------------- /var/summary: -------------------------------------------------------------------------------- 1 | Ruby Facets in C 2 | -------------------------------------------------------------------------------- /lib/carats.rb: -------------------------------------------------------------------------------- 1 | require 'carats/hash_rekey.so' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | rubies 2 | ext/**/Makefile 3 | *.so 4 | tmp 5 | -------------------------------------------------------------------------------- /var/copyrights: -------------------------------------------------------------------------------- 1 | --- 2 | - 2012 Rubyworks (BSD-2-Clause) 3 | -------------------------------------------------------------------------------- /var/requirements: -------------------------------------------------------------------------------- 1 | --- 2 | - rake-compiler (build) 3 | 4 | -------------------------------------------------------------------------------- /var/authors: -------------------------------------------------------------------------------- 1 | --- 2 | - Thomas Sawyer 3 | -------------------------------------------------------------------------------- /lib/carats/hash/rekey.rb: -------------------------------------------------------------------------------- 1 | require 'carats/core_ext/hash_rekey' 2 | -------------------------------------------------------------------------------- /lib/carats/string/splice.rb: -------------------------------------------------------------------------------- 1 | require 'carats/core_ext/string_splice' 2 | -------------------------------------------------------------------------------- /lib/carats/kernel/identical.rb: -------------------------------------------------------------------------------- 1 | require 'carats/core_ext/kernel_identical' 2 | -------------------------------------------------------------------------------- /var/repositories: -------------------------------------------------------------------------------- 1 | --- 2 | upstream: git://github.com/rubyworks/carats.git 3 | -------------------------------------------------------------------------------- /task/assembly.rb: -------------------------------------------------------------------------------- 1 | --- 2 | grancher: 3 | service: Grancher 4 | active : true 5 | 6 | -------------------------------------------------------------------------------- /site/assets/fork-me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyworks/carats/master/site/assets/fork-me.png -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | # COPYRIGHT NOTICES 2 | 3 | Copyright (c) 2010 Caleb Clausen 4 | 5 | * Hash#rekey 6 | 7 | 8 | -------------------------------------------------------------------------------- /site/assets/images/carrot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyworks/carats/master/site/assets/images/carrot.jpg -------------------------------------------------------------------------------- /ext/hash/rekey/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/hash/rekey' 3 | create_makefile 'hash_rekey' 4 | 5 | -------------------------------------------------------------------------------- /ext/basicobject/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/basicobject' 3 | create_makefile 'basicobject' 4 | 5 | -------------------------------------------------------------------------------- /ext/array/each_pair/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/array/each_pair' 3 | create_makefile 'array_each_pair' 4 | -------------------------------------------------------------------------------- /ext/hash/op_push/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/hash/op_push' 3 | create_makefile 'hash_op_push' 4 | 5 | -------------------------------------------------------------------------------- /ext/string/splice/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/string/splice' 3 | create_makefile 'string_splice' 4 | 5 | -------------------------------------------------------------------------------- /ext/kernel/identical/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/array/identical' 3 | create_makefile 'kernel_identical' 4 | -------------------------------------------------------------------------------- /ext/kernel/required/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/kernel/required' 3 | create_makefile 'kernel_required' 4 | 5 | -------------------------------------------------------------------------------- /ext/array/each_value/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/array/each_value' 3 | create_makefile 'array_each_value' 4 | 5 | -------------------------------------------------------------------------------- /ext/hash/slice/README.md: -------------------------------------------------------------------------------- 1 | # Hash#slice 2 | 3 | ## About 4 | 5 | The `Hash#slice` method reduces a hash to only the specified keys. 6 | 7 | -------------------------------------------------------------------------------- /ext/kernel/truefalse/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/kernel/truefalse' 3 | create_makefile 'kernel_truefalse' 4 | 5 | -------------------------------------------------------------------------------- /ext/module/anonymous/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/module/anonymous' 3 | create_makefile 'module_anonymous' 4 | 5 | -------------------------------------------------------------------------------- /ext/kernel/require_path/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | #create_makefile 'carats/kernel/require_path' 3 | create_makefile 'kernel_require_path' 4 | 5 | -------------------------------------------------------------------------------- /ext/array/each_value/each_value.rb: -------------------------------------------------------------------------------- 1 | class Array 2 | # Alias for #each. The intention of this method 3 | # is to provide polymorphism with Hash. 4 | alias :each_value :each 5 | end 6 | 7 | -------------------------------------------------------------------------------- /ext/kernel/identical/identical.rb: -------------------------------------------------------------------------------- 1 | module Kernel 2 | 3 | # Does self and other refer to the identical object? 4 | def identical?(other) 5 | object_id == other.object_id 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /ext/null/extconf.rb: -------------------------------------------------------------------------------- 1 | # Loads mkmf which is used to make makefiles for Ruby extensions 2 | require 'mkmf' 3 | 4 | # Give it a name 5 | extension_name = 'null' 6 | 7 | # The destination 8 | dir_config(extension_name) 9 | 10 | # Do the work 11 | create_makefile(extension_name) 12 | 13 | -------------------------------------------------------------------------------- /ext/array/each_pair/each_pair.rb: -------------------------------------------------------------------------------- 1 | class Array 2 | 3 | # Iterate over index and value. The intention of this 4 | # method is to provide polymorphism with Hash. 5 | # 6 | def each_pair #:yield: 7 | i = -1 8 | each_value do |x| 9 | yield(i+=1, x) 10 | end 11 | end 12 | 13 | end 14 | 15 | -------------------------------------------------------------------------------- /ext/kernel/required/README.md: -------------------------------------------------------------------------------- 1 | # Kernel#required? 2 | 3 | ## About 4 | 5 | How can one tell if a feature has already been loaded? Turns out there 6 | is no reasonable way to do so it pure Ruby. This method rememdies that. 7 | 8 | required?('facets') #=> false 9 | require 'facets' 10 | required?('facets') #=> true 11 | 12 | -------------------------------------------------------------------------------- /ext/hash/op_push/op_push.rb: -------------------------------------------------------------------------------- 1 | class Hash 2 | 3 | # Can be used like update, or passed a two-element 4 | # `[key,value]` array. 5 | # 6 | # Credit: Trans 7 | 8 | def <<(other) 9 | if other.respond_to?(:to_ary) 10 | self.store(*other) 11 | else 12 | update(other) 13 | end 14 | self 15 | end 16 | 17 | end 18 | -------------------------------------------------------------------------------- /work/step/lib/step/itimer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * itimer.h -- Interval timer 3 | */ 4 | 5 | 6 | #ifndef __ITIMER_H__ 7 | #define __ITIMER_H__ 8 | 9 | #include 10 | 11 | 12 | extern VALUE rb_process_setitimer( int, VALUE *, VALUE); 13 | extern VALUE rb_process_getitimer( VALUE obj); 14 | 15 | extern void Init_itimer( void); 16 | 17 | #endif 18 | 19 | -------------------------------------------------------------------------------- /work/prelude.rb.yaml.patch: -------------------------------------------------------------------------------- 1 | *** prelude.rb.1.9.3-p0 2011-11-12 15:42:38.000000000 +0900 2 | --- prelude.rb 2011-11-12 15:38:42.000000000 +0900 3 | *************** 4 | *** 29,31 **** 5 | --- 29,38 ---- 6 | } 7 | end 8 | end 9 | + 10 | + class String 11 | + def __yaml__ 12 | + require 'yaml' 13 | + YAML.load self[0..-3] 14 | + end 15 | + end 16 | -------------------------------------------------------------------------------- /ext/kernel/require_path/README.md: -------------------------------------------------------------------------------- 1 | # Kernel#require_path 2 | 3 | ## About 4 | 5 | How can we know where a feature will be loaded from when it is required? 6 | Presently Ruby provided no way to know this, even though the functionaliy 7 | to do so is just below the surfarce. The `Kernel#require_path` exposes 8 | it. 9 | 10 | require_path('realms') 11 | => "/opt/Ruby/1.9.3-p327/lib/ruby/site_ruby/1.9.1/realms.rb" 12 | 13 | -------------------------------------------------------------------------------- /ext/basicobject/README.md: -------------------------------------------------------------------------------- 1 | # BasicObject 2 | 3 | BasicObject is built-in to Ruby 1.9. The class included with Carats is provided 4 | for Ruby 1.8.x users. Considering the Ruby 1.9 has finally started to go mainstream, 5 | this library is reapidly becoming obsolete and so it will probably be removed 6 | in future version, say around Jan 1 2014. 7 | 8 | It is not included in the common set of extensions loaded when calling `require 'carats'`. 9 | -------------------------------------------------------------------------------- /ext/array/each_value/array_each_value.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * ary.each_value { |item| block } -> ary 7 | * ary.each_value -> Enumerator 8 | * 9 | * This method is a simple alias for #each. 10 | * 11 | * The method provides polymorphism with Hash#each_value. 12 | * 13 | */ 14 | 15 | void Init_carats(){ 16 | rb_define_alias(rb_cArray, "each_value", "each"); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /ext/array/each_value/README.md: -------------------------------------------------------------------------------- 1 | # Array#each_value 2 | 3 | ## About 4 | 5 | The `Array#each_value` method is a simply a analog to `Hash#each_value`, 6 | and does essentially the same thing. Implementation wise it is just 7 | an alias for `Array#each`. 8 | 9 | [:a, :b, :c].each_value do |item| 10 | p index, item 11 | end 12 | 13 | :a 14 | :b 15 | :c 16 | 17 | Its purpose is simply to enhance polymorphism bewtween Array and Hash. 18 | 19 | -------------------------------------------------------------------------------- /ext/array/each_pair/README.md: -------------------------------------------------------------------------------- 1 | # Array#each_pair 2 | 3 | ## About 4 | 5 | The `Array#each_pair` method is a simply a analog to `Hash#each_pair`, and 6 | does essentially the same thing, but instead of the hash key it iterates 7 | with the array index. 8 | 9 | [:a, :b, :c].each_pair do |index, item| 10 | p [index, item] 11 | end 12 | 13 | [1, :a] 14 | [2, :b] 15 | [3, :c] 16 | 17 | Its purpose is simply to enhance polymorphism bewtween Array and Hash. 18 | 19 | -------------------------------------------------------------------------------- /work/step/lib/mkrf_conf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env autorake 2 | 3 | # 4 | # mkrf_conf -- configure Step 5 | # 6 | 7 | require "rbconfig" 8 | 9 | incdir_ruby RbConfig::CONFIG[ "topdir"] 10 | 11 | if RUBY_VERSION <= "1.8.6" then 12 | enable_array_index_with_block 13 | enable_kernel_tap 14 | else 15 | disable_array_index_with_block 16 | disable_kernel_tap 17 | end 18 | 19 | have_header "ruby.h" 20 | have_header "st.h" 21 | have_header "rubyio.h" 22 | have_header "re.h" 23 | 24 | # vim:set ft=ruby : 25 | -------------------------------------------------------------------------------- /ext/kernel/truefalse/kernel_truefalse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void Init_kernel_truefalse(){ 5 | rb_define_method(rb_mKernel, "true?", rb_false, 0); 6 | rb_define_method(rb_mKernel, "false?", rb_false, 0); 7 | 8 | rb_define_method(rb_cTrueClass, "true?", rb_true, 0); 9 | rb_define_method(rb_cTrueClass, "false?", rb_false, 0); 10 | 11 | rb_define_method(rb_cFalseClass, "true?", rb_false, 0); 12 | rb_define_method(rb_cFalseClass, "false?", rb_true, 0); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # We use rake-compiler for this project. 4 | require 'rake/extensiontask' 5 | 6 | lib_dir = 'lib/carats/core_ext' 7 | 8 | Dir['ext/**/*.c'].each do |ext| 9 | next unless File.exist?(File.dirname(ext) + '/extconf.rb') 10 | 11 | ext_name = File.basename(ext).chomp('.c') 12 | ext_dir = File.dirname(ext) 13 | 14 | Rake::ExtensionTask.new(ext_name) do |ext| 15 | ext.ext_dir = ext_dir 16 | ext.lib_dir = lib_dir 17 | ext.tmp_dir = 'tmp' 18 | end 19 | end 20 | 21 | -------------------------------------------------------------------------------- /ext/kernel/truefalse/README.md: -------------------------------------------------------------------------------- 1 | # true? & false? 2 | 3 | ## About 4 | 5 | We have `#nil?` which returns `true` only if the receiver is the one and only 6 | `NilClass` instance. Here we simply provide the same for `TrueClass` and `FalseClass`. 7 | 8 | true.true? #=> true 9 | false.true? #=> false 10 | nil.true? #=> false 11 | "foo".true? #=> false 12 | 13 | true.false? #=> false 14 | false.false? #=> true 15 | nil.false? #=> false 16 | "foo".false? #=> false 17 | 18 | -------------------------------------------------------------------------------- /ext/kernel/required/kernel_required.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * required?('carats/required') -> true/false 7 | * 8 | * Returns true or false whether a feature has been required or not. 9 | * 10 | */ 11 | 12 | VALUE 13 | rb_f_required(VALUE obj, VALUE fname){ 14 | if(rb_provided(RSTRING_PTR(fname))){ 15 | return(Qtrue); 16 | } else { 17 | return(Qfalse); 18 | }; 19 | } 20 | 21 | void Init_kernel_required(){ 22 | rb_define_global_function("required?", rb_f_required, 1); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /ext/module/is/README.md: -------------------------------------------------------------------------------- 1 | # Is 2 | 3 | ## Bounty! 4 | 5 | There is a $20 Bounty for this feature. 6 | 7 | ## About 8 | 9 | A module method that works like #include and #extend combined. It 10 | includes at the instance level and extends at the class-level. 11 | 12 | Here is a testable example: 13 | 14 | module Demonstratable 15 | def self.y; "y"; end 16 | def x; "x"; end 17 | end 18 | 19 | class Example 20 | is Demonstratable 21 | end 22 | 23 | Example.y #=> "y" 24 | Example.new.x #=> "x" 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ext/string/splice/README.md: -------------------------------------------------------------------------------- 1 | # String#splice 2 | 3 | ## About 4 | 5 | String#slice is essentially the same as #[]=. 6 | But it acts like #slice! when given a single argument. 7 | 8 | a = "HELLO" 9 | a.splice(1, "X") 10 | a #=> "HXLLO" 11 | 12 | a = "HELLO" 13 | a.splice(1) #=> "E" 14 | a #=> "HLLO" 15 | 16 | Returns the string with changes made or new sub-string. [String] 17 | 18 | Note: New implementation can take three arguments for 19 | begin and end indexes, e.g. `splice(beg, end, sub)`. 20 | 21 | -------------------------------------------------------------------------------- /ext/kernel/truefalse/truefalse.rb: -------------------------------------------------------------------------------- 1 | module Kernel 2 | 3 | # Returns true is an object is class TrueClass, 4 | # otherwise false. 5 | # 6 | # true.true? #=> true 7 | # false.true? #=> false 8 | # nil.true? #=> false 9 | # 10 | def true? 11 | (true == self) 12 | end 13 | 14 | # Returns true is an object is class FalseClass, 15 | # otherwise false. 16 | # 17 | # true.false? #=> false 18 | # false.false? #=> true 19 | # nil.false? #=> false 20 | # 21 | def false? 22 | (false == self) 23 | end 24 | 25 | end 26 | 27 | -------------------------------------------------------------------------------- /ext/kernel/require_path/kernel_require_path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * require_path('carats/required') -> string 7 | * 8 | * Returns the absolute path a feature. 9 | * 10 | */ 11 | 12 | VALUE 13 | rb_f_require_path(VALUE obj, VALUE fname){ 14 | VALUE path; 15 | found = search_required(fname, &path, rb_safe_level()); 16 | if (found) { 17 | return(path); 18 | } else { 19 | return(Qnil); 20 | } 21 | } 22 | 23 | void Init_require_path(){ 24 | rb_define_global_function("require_path", rb_f_require_path, 1); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /work/name.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/core/facets/unboundmethod/name.rb b/lib/core/facets/unboundmethod/name.rb 2 | index 29bfe76..a411e2c 100644 3 | --- a/lib/core/facets/unboundmethod/name.rb 4 | +++ b/lib/core/facets/unboundmethod/name.rb 5 | @@ -1,11 +1,12 @@ 6 | unless (RUBY_VERSION[0,3] == '1.9') 7 | 8 | class UnboundMethod 9 | 10 | # Return the name of the method. 11 | - # Is this already in 1.9+ ? 12 | + # Be aware that in ruby 1.9 UnboundMethod#name is defined already, but it 13 | + # returns a Symbol not a String. 14 | # 15 | # class X 16 | # def foo; end 17 | # end 18 | # 19 | -------------------------------------------------------------------------------- /ext/kernel/identical/README.md: -------------------------------------------------------------------------------- 1 | # Kernel#identical? 2 | 3 | ## About 4 | 5 | The `Kernel#equal?` method is a terrible name for that method. 6 | By using it to mean "one and the same", Ruby is forced to use 7 | more cryptic methods like `#eql?` for more usual meanings. 8 | 9 | Worse still for test frameworks that need to define ssertions 10 | for these methods. Consider for instance what `#assert_equal` 11 | means. 12 | 13 | To push back against this we introduce the `#indentical?` method 14 | which does the the same thing a `#equal?`. With any fortune 15 | one day `#identical?` will completely supplant `#equal?` in 16 | general usage. 17 | 18 | -------------------------------------------------------------------------------- /work/step/lib/Rakefile: -------------------------------------------------------------------------------- 1 | # 2 | # Rakefile -- build some libraries 3 | # 4 | 5 | 6 | require "rake/autorake" 7 | 8 | extend Rake::Configure 9 | 10 | 11 | rule ".o" => ".c" do |t| 12 | cc t.name, t.source, "-O2", "-fPIC" 13 | end 14 | 15 | 16 | DLs = { 17 | "step.so" => "step.o", 18 | "step/filesys.so" => "step/filesys.o", 19 | "step/itimer.so" => "step/itimer.o", 20 | } 21 | 22 | DLs.each { |k,v| 23 | task k => v do |t| 24 | ld t.name, t.prerequisites, "-shared" 25 | end 26 | } 27 | 28 | 29 | task :default => DLs.keys 30 | 31 | 32 | task :clean do 33 | FileList[ "*.o", "*.so"].each { |f| rm_f f } 34 | end 35 | 36 | -------------------------------------------------------------------------------- /ext/module/anonymous/README.md: -------------------------------------------------------------------------------- 1 | # Module#anonymous 2 | 3 | ## About 4 | 5 | Technically one can determine if a module is anonymous, which means it 6 | is not referenced by any constant, by checking to see if it has a name. 7 | For example `Object` is not anonymous b/c it has a name. 8 | 9 | Object.name #=> "Object" 10 | 11 | But if we create a module via `Module.new` then it would not. 12 | 13 | m = Module.new 14 | m.name #=> nil 15 | 16 | Such a module is anonymous. 17 | 18 | m.anonymous? #=> true 19 | 20 | In addition, if a module as *no* anonymous instances it is said to 21 | be permanent. 22 | 23 | m.permanent? #=> false 24 | 25 | -------------------------------------------------------------------------------- /ext/string/margin/README.md: -------------------------------------------------------------------------------- 1 | # String#margin 2 | 3 | ## Bounty 4 | 5 | There is a $10 bounty for this method. This is similar to the #indent method, 6 | so if that boubty is completed this method should be a pretty easy derivation. 7 | 8 | ## About 9 | 10 | String#margin preserve relative indention such that the line with the least 11 | amount of white space ends up with the given number of spaces before non-space 12 | characters and all other lines move relative to it. 13 | 14 | Because of the nature of this method any leading tab characters (`\t`) must 15 | be converted to spaces. The size of a tab can be set via the `:tab` option. 16 | The default size is 2. 17 | 18 | -------------------------------------------------------------------------------- /ext/module/anonymous/anonymous.rb: -------------------------------------------------------------------------------- 1 | class Module 2 | 3 | # A module may or may not have a name. 4 | # 5 | # module M; end 6 | # M.name # => "M" 7 | # 8 | # m = Module.new 9 | # m.name # => "" 10 | # 11 | # A module gets a name when it is first assigned to a constant. Either 12 | # via the +module+ or +class+ keyword or by an explicit assignment: 13 | # 14 | # m = Module.new # creates an anonymous module 15 | # M = m # => m gets a name here as a side-effect 16 | # m.name # => "M" 17 | # 18 | def anonymous? 19 | # The name of an anonymous class is an empty 20 | # string in 1.8, and nil in 1.9. 21 | name.nil? || name.empty? 22 | end 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /ext/string/indent/string_indent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * str.indent(n, c) -> new_str 7 | * 8 | * Indent a string by inserting a number of spaces before each line. 9 | * Optionally use a different character besides a space. 10 | * 11 | */ 12 | 13 | VALUE 14 | rb_str_indent(VALUE num, VALUE chr) 15 | { 16 | int n = NUM2LONG(num) 17 | if (n >= 0) 18 | str_gsub(/^/, rb_str_times(chr, num)) 19 | else 20 | str_gsub(/^#{Regexp.escape(c)}{0,#{-n}}/, "") 21 | end 22 | 23 | } 24 | 25 | void Init_carats(){ 26 | rb_define_method(rb_cString, "indent", rb_str_indent, 2); 27 | 28 | /* TODO: alias as tab? */ 29 | 30 | } 31 | 32 | -------------------------------------------------------------------------------- /ext/module/is/module_is.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * module.is other_module -> module 7 | * 8 | * A module method that works like #include and #extend combined. 9 | * It includes at the instance level and extends at the class-level. 10 | * 11 | * module Demonstratable 12 | * def self.y; "y"; end 13 | * def x; "x"; end 14 | * end 15 | * 16 | * class Example 17 | * is Demonstratable 18 | * end 19 | * 20 | * Example.y #=> "y" 21 | * Example.new.x #=> "x" 22 | * 23 | */ 24 | 25 | VALUE 26 | rb_module_is(VALUE module){ 27 | 28 | } 29 | 30 | void Init_carats(){ 31 | rb_define_method(rb_cModule, "is", rb_module_is, 0); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /.index: -------------------------------------------------------------------------------- 1 | --- 2 | revision: 2013 3 | type: ruby 4 | sources: 5 | - var 6 | - VERSION 7 | authors: 8 | - name: Thomas Sawyer 9 | email: transfire@gmail.com 10 | organizations: [] 11 | requirements: 12 | - groups: 13 | - build 14 | development: true 15 | name: rake-compiler 16 | conflicts: [] 17 | alternatives: [] 18 | resources: [] 19 | repositories: 20 | - name: upstream 21 | scm: git 22 | uri: git://github.com/rubyworks/carats.git 23 | categories: [] 24 | copyrights: 25 | - holder: Rubyworks 26 | year: '2012' 27 | license: BSD-2-Clause 28 | customs: [] 29 | paths: 30 | lib: 31 | - lib 32 | created: '2004-09-01' 33 | summary: Ruby Facets in C 34 | title: Carats 35 | name: carats 36 | version: 0.4.0 37 | date: '2013-01-28' 38 | -------------------------------------------------------------------------------- /ext/null/null.c: -------------------------------------------------------------------------------- 1 | // Include the Ruby headers and goodies 2 | #include 3 | 4 | /* 5 | * Document-class: NullClass 6 | * 7 | * The class of the singleton object null. 8 | */ 9 | 10 | VALUE rb_cNullClass; 11 | 12 | void 13 | Init_null() { 14 | 15 | rb_cNullClass = rb_define_class("NullClass", rb_cNilClass); 16 | 17 | SPECIAL_SINGLETON(Qnull, rb_cNullClass); 18 | 19 | static VALUE 20 | method_missing(int argc, VALUE * argv, VALUE self) { 21 | return Qnull; 22 | } 23 | 24 | rb_define_method(rb_cNullClass, "null?", rb_true, 0); 25 | rb_define_method(rb_cNullClass, "method_missing", method_missing, -1); 26 | 27 | /* 28 | * An alias of +null+ 29 | */ 30 | rb_define_global_const("NULL", Qnull); 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /ext/hash/rekey/hash_rekey.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * hsh.rekey -> Hash 7 | * hsh.rekey(old_key=>new_key, ...) -> Hash 8 | * hsh.rekey { |k| new_key } -> Hash 9 | * hsh.rekey { |k,v| new_key } -> Hash 10 | * 11 | * Rekeys a hash, returning a new hash with the keys changed. 12 | * 13 | * TODO: Finish implementation. 14 | * 15 | */ 16 | 17 | VALUE 18 | rb_hash_rekey(VALUE self){ 19 | VALUE result=rb_obj_dup(self); 20 | rb_hash_foreach(self, rekey_i, result); 21 | return result; 22 | } 23 | 24 | static int rekey_i(VALUE k, VALUE v, VALUE result){ 25 | VALUE nk=rb_yield(k); 26 | if (RTEST(nk)) 27 | rb_hash_aset(result,nk,rb_hash_delete(result,k)); 28 | return ST_CONTINUE; 29 | } 30 | 31 | void Init_carats(){ 32 | rb_define_method(rb_cHash, "rekey", rb_hash_rekey, 0); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /ext/hash/op_push/README.md: -------------------------------------------------------------------------------- 1 | # Hash#<< 2 | 3 | ## About 4 | 5 | Such a lovely little method, one has to wonder why Ruby doesn't have it. 6 | The simplist and primary usage is to merge a key-value pair into a hash. 7 | 8 | {:a=>1} << [:b, 2] 9 | => {:a=>1, :b=>2} 10 | 11 | It can also take an array of even number of elements of any length. 12 | 13 | {:a=>1} << [:b, 2, :c, 3] 14 | => {:a=>1, :b=>2, :c=>3} 15 | 16 | That's really the heart of the matter. But because it just minor addition 17 | to to the method it can also take another hash, in which case it acts just 18 | like merge. 19 | 20 | {:a=>1} << {:b=>2} 21 | => {:a=>1, :b=>2} 22 | 23 | 24 | ## Pairs? 25 | 26 | If Ruby had built-in support for the concept of a `Pair` and a literal 27 | notation to go with it, we probably would not allow the later two forms 28 | at all and limit the first form to pairs only. But since we have to use 29 | Arrays to represent the pairs, the later forms are reasonable. 30 | 31 | -------------------------------------------------------------------------------- /work/step/lib/step/filesys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * filesys.h -- File system tools 3 | */ 4 | 5 | #ifndef __FILESYS_H__ 6 | #define __FILESYS_H__ 7 | 8 | #include 9 | 10 | 11 | extern VALUE rb_fsstat_s_alloc( VALUE); 12 | extern VALUE rb_fsstat_init( VALUE, VALUE); 13 | extern VALUE rb_fsstat_init_copy( VALUE, VALUE); 14 | 15 | extern VALUE rb_fsstat_type( VALUE); 16 | extern VALUE rb_fsstat_bsize( VALUE); 17 | extern VALUE rb_fsstat_blocks( VALUE); 18 | extern VALUE rb_fsstat_bfree( VALUE); 19 | extern VALUE rb_fsstat_bavail( VALUE); 20 | extern VALUE rb_fsstat_files( VALUE); 21 | extern VALUE rb_fsstat_ffree( VALUE); 22 | extern VALUE rb_fsstat_fsid( VALUE); 23 | 24 | extern VALUE rb_fsstat_bytes( VALUE); 25 | extern VALUE rb_fsstat_free( VALUE); 26 | extern VALUE rb_fsstat_avail( VALUE); 27 | extern VALUE rb_fsstat_pfree( VALUE); 28 | extern VALUE rb_fsstat_pavail( VALUE); 29 | 30 | extern VALUE rb_fsstat_inspect( VALUE); 31 | 32 | extern void Init_filesys( void); 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /ext/module/anonymous/module_anonymous.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * module.anonymous? -> true/false 7 | * 8 | * Returns false if a module or class is referenced by constant. 9 | * 10 | */ 11 | 12 | VALUE 13 | rb_mod_anonymous(VALUE mod) 14 | { 15 | int permanent; 16 | VALUE path = classname(mod, &permanent); 17 | 18 | if (!NIL_P(path)) return Qtrue; 19 | return Qfalse; 20 | } 21 | 22 | /* 23 | * call-seq: 24 | * module.permanent? -> true/false 25 | * 26 | * A class or module is "permanent", that means it has no 27 | * anonymous names. 28 | * 29 | */ 30 | 31 | VALUE 32 | rb_mod_permanent(VALUE mod) 33 | { 34 | int permanent; 35 | VALUE path = classname(mod, &permanent); 36 | 37 | if (permanent) return Qtrue; 38 | return Qfalse; 39 | } 40 | 41 | void Init_carats(){ 42 | rb_define_method(rb_cModule, "anonymous?", rb_mod_anonymous, 0); 43 | rb_define_method(rb_cModule, "permanent?", rb_mod_permanent, 0); 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /ext/string/splice/splice.rb: -------------------------------------------------------------------------------- 1 | require 'facets/string/store' 2 | 3 | class String 4 | 5 | # String#slice is essentially the same as #store. 6 | # But it acts like #slice! when given a single argument. 7 | # 8 | # idx - index [Integer] 9 | # sub - a substitute string (optional) [String] 10 | # 11 | # Examples 12 | # 13 | # a = "HELLO" 14 | # a.splice(1, "X") 15 | # a #=> "HXLLO" 16 | # 17 | # a = "HELLO" 18 | # a.splice(1) #=> "E" 19 | # a #=> "HLLO" 20 | # 21 | # Returns the string with changes made or new sub-string. [String] 22 | # 23 | # Note: New implementation can take three arguments for 24 | # begin and end indexes, e.g. `splice(beg, end, sub)`. 25 | # 26 | # Credit: Trans 27 | 28 | def splice(idx, sub=nil) 29 | if sub 30 | store(idx, sub) 31 | else 32 | case idx 33 | when Range 34 | slice!(idx) 35 | else 36 | slice!(idx,1) 37 | end 38 | end 39 | end 40 | 41 | end 42 | 43 | -------------------------------------------------------------------------------- /ext/kernel/identical/kernel_identical.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * obj.identical?(other) -> true or false 7 | * 8 | * Identity --- For all objects, identical? returns 9 | * true only if +obj+ and +other+ are one and the same object. 10 | * 11 | * The identical? method should never be overridden by subclasses 12 | * as it is used to determine object identity (that is, a.identical?(b) 13 | * if and only if a is the same object as b): 14 | * 15 | * obj = "a" 16 | * other = obj.dup 17 | * 18 | * a == other #=> true 19 | * a.identical? other #=> false 20 | * a.idential? a #=> true 21 | * 22 | */ 23 | 24 | VALUE 25 | rb_obj_identical(VALUE obj1, VALUE obj2) 26 | { 27 | if (obj1 == obj2) return Qtrue; 28 | return Qfalse; 29 | } 30 | 31 | void Init_kernel_identical(){ 32 | rb_define_method(rb_cObject, "identical?", rb_obj_identical, 0); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /ext/array/each_pair/array_each_pair.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * ary.each_pair { |index, item| block } -> ary 7 | * ary.each_pair -> Enumerator 8 | * 9 | * Calls the given block once for each element in +self+, passing that index 10 | * and element as a parameter. 11 | * 12 | * An Enumerator is returned if no block is given. 13 | * 14 | * This method provides polymorphism with Hash#each_pair. 15 | * 16 | * a = [ "a", "b", "c" ] 17 | * a.each_pair {|i, x| print i, x, " -- " } 18 | * 19 | * produces: 20 | * 21 | * 0a -- 1b -- 2c -- 22 | */ 23 | 24 | VALUE 25 | rb_ary_each_pair(VALUE array) 26 | { 27 | long i; 28 | volatile VALUE ary = array; 29 | 30 | RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); 31 | for (i=0; i 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * str.splice(int, rstr) -> str 7 | * 8 | * String#splice is a combinatin of #[] and #[]=. With to 9 | * or three arguments it acts like #[]=. 10 | * 11 | * a = "HELLO" 12 | * a.splice(1, "X") 13 | * a #=> "HXLLO" 14 | * 15 | * But it acts like #slice! when given a single argument. 16 | * 17 | * a = "HELLO" 18 | * a.splice(1) #=> "E" 19 | * a #=> "HLLO" 20 | * 21 | */ 22 | 23 | VALUE 24 | rb_str_splice2(int argc, VALUE *argv, VALUE str) 25 | { 26 | if (argc == 3) { 27 | rb_str_splice(str, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]); 28 | return(str); 29 | } else if (argc = 2) { 30 | rb_str_aset(str, argv[0], argv[1]); 31 | return(str); 32 | } else if (argc = 1) { 33 | return rb_str_aref(str, argv[0]); 34 | } else { 35 | rb_check_arity(argc, 1, 3); 36 | } 37 | } 38 | 39 | void Init_string_splice(){ 40 | rb_define_method(rb_cString, "splice", rb_str_splice2, -1); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /ext/hash/rekey/README.md: -------------------------------------------------------------------------------- 1 | # Hash#rekey 2 | 3 | ## Bounty 4 | 5 | There is a $10 bounty for finishing this method. Part of the implementation 6 | has already be completed by Calib Clausen. 7 | 8 | ## About 9 | 10 | The `Hash#rekey` method is sorely missing from Ruby. It's purpose it too 11 | convert the keys of hash via a block. 12 | 13 | {'a'=>'X', 'b'=>'Y'}.rekey{ |k| k.to_sym } 14 | => {:a=>'X', :b=>'Y'} 15 | 16 | Since converting keys to symbols is one of the most, if not the most, 17 | common conversion that is the default if no block is given. 18 | 19 | {'a'=>'X', 'b'=>'Y'}.rekey 20 | => {:a=>'X', :b=>'Y'} 21 | 22 | The block can also take a key-value pair if the value is needed to 23 | determine the key. 24 | 25 | {'a'=>'X', 'b'=>'Y'}.rekey{ |k,v| "#{k}{v}".to_sym } 26 | => {:aX=>'X', :bY=>'Y'} 27 | 28 | Finally the method can take key paramters for specific key conversions. 29 | 30 | {'a'=>'X', 'b'=>'Y'}.rekey('a'=>'q') 31 | => {'q'=>'X', 'b'=>'Y'} 32 | 33 | If both key parameters and a block are given, the key parameters are 34 | applied first, and then the block. 35 | 36 | -------------------------------------------------------------------------------- /work/step/lib/step.h: -------------------------------------------------------------------------------- 1 | /* 2 | * step.h -- Simple Ruby Extensions 3 | */ 4 | 5 | 6 | #ifndef __STEP_H__ 7 | #define __STEP_H__ 8 | 9 | #include 10 | 11 | 12 | extern VALUE rb_str_notempty( VALUE str); 13 | extern VALUE rb_str_eat( int, VALUE *, VALUE); 14 | extern VALUE rb_str_cut_bang( VALUE, VALUE); 15 | extern VALUE rb_str_clear( VALUE); 16 | extern VALUE rb_str_head( VALUE, VALUE); 17 | extern VALUE rb_str_rest( VALUE, VALUE); 18 | extern VALUE rb_str_tail( VALUE, VALUE); 19 | extern VALUE rb_str_starts_with( VALUE, VALUE); 20 | extern VALUE rb_str_ends_with( VALUE, VALUE); 21 | extern VALUE rb_ary_notempty( VALUE); 22 | extern VALUE rb_ary_indexes( VALUE); 23 | extern VALUE rb_ary_pick( VALUE); 24 | extern VALUE rb_ary_rpick( VALUE); 25 | #ifdef ARRAY_INDEX_WITH_BLOCK 26 | extern VALUE rb_ary_index( int, VALUE *, VALUE); 27 | extern VALUE rb_ary_rindex( int, VALUE *, VALUE); 28 | #endif 29 | extern VALUE rb_int_grammatical( VALUE, VALUE, VALUE); 30 | extern VALUE rb_hash_notempty( VALUE); 31 | extern VALUE rb_file_size( VALUE); 32 | extern VALUE rb_match_begin( int, VALUE *, VALUE); 33 | extern VALUE rb_match_end( int, VALUE *, VALUE); 34 | 35 | extern void Init_step( void); 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /ext/string/indent/README.md: -------------------------------------------------------------------------------- 1 | # String#indent 2 | 3 | ## Bounty 4 | 5 | There is a $20 bounty for a good implementation of indent and unindent. 6 | A good implmentation should not rely on regular expressions. 7 | 8 | ## About 9 | 10 | String#indent is used to indent a String a given number of spaces. 11 | Optionally a diferrent string can be used for the "indention" besides 12 | a space. 13 | 14 | The #indent method is aliased as #tab (as that is the typical modern use 15 | of the tab key these days). And there is a complementary `#unindent` method 16 | (or should it be `#undent`?) along with it's alias `backtab`. 17 | 18 | ## Implementation 19 | 20 | The basic implementation is to iterate over each line of a string and prefix 21 | the tab character the specified number of times. But I came acorss this 22 | implementation on the Internet that claimed superior design: 23 | 24 | def indent(count, char = ' ') 25 | gsub(/([^\n]*)(\n|$)/) do |match| 26 | last_iteration = ($1 == "" && $2 == "") 27 | line = "" 28 | line << (char * count) unless last_iteration 29 | line << $1 30 | line << $2 31 | line 32 | end 33 | 34 | But it this really a better implementation for some reason? 35 | 36 | -------------------------------------------------------------------------------- /ext/null/README.md: -------------------------------------------------------------------------------- 1 | # Null 2 | 3 | ## Bounty! 4 | 5 | The NullClass has yet to be fully implemented. There are issues a more 6 | experienced Ruby C expert needs to work out. 7 | 8 | There is a $20 bounty for this class. 9 | 10 | ## About 11 | 12 | NullClass is just like NilClass with one exception -- missing methods 13 | always return +null+. 14 | 15 | Because +null+ evaluates as false, just like +nil+ and +false+, +null+ 16 | makes it very convenient to to query method chains that might not exist. 17 | 18 | Here is a classic example: 19 | 20 | class Config 21 | def initialize(data={}) 22 | @data = data 23 | end 24 | 25 | def method_missing(name) 26 | value = @data[name] || null 27 | Hash === value ? Config.new(value) : value 28 | end 29 | end 30 | 31 | config = Config.new(:x=>{:a=>'A'}) 32 | 33 | config.x.a #=> 'X' 34 | config.x.y #=> null 35 | 36 | if config.x.y.z 37 | # will not happen, but not an error either 38 | end 39 | 40 | Null is useful when working with nested data, in that it does not require 41 | the data's user to continually check for possible +nil+ values to circumvent 42 | NoMethodErrors. 43 | 44 | ## Note 45 | 46 | Would `NA`, for Non-Applicable, be a better name for this class? 47 | -------------------------------------------------------------------------------- /ext/hash/op_push/hash_op_push.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * call-seq: 6 | * hsh << obj -> hsh 7 | * 8 | * Append---Pushes the given object into this hash. The object 9 | * can be another hash or array of pairs. This expression returns 10 | * the hash itself, so several appends may be chained together. 11 | * 12 | * { :a=>1 } << [:b, 2] << { :c=>3 } 13 | * #=> { :a=>1, :b=>2, :c=>3 } 14 | * 15 | */ 16 | 17 | VALUE 18 | rb_hsh_push(VALUE hsh, VALUE obj) 19 | { 20 | if (rb_respond_to(obj, rb_intern("to_hash"))) { 21 | rb_hash_update(hsh, obj) /* env_update(hsh, obj) */ 22 | } 23 | else if (rb_respond_to(obj, rb_intern("to_ary"))) { 24 | VALUE ary = rb_convert_type(obj, T_ARRAY, "Array", "to_ary"); 25 | long size = RARRAY_LEN(ary); 26 | if(size & 1) { 27 | rb_raise(rb_eArgError, "odd number of arguments for Hash"); 28 | } 29 | else { 30 | /* TODO: would it be better to convert the array to a hash then use update? */ 31 | for (i=0; i1, :b=>2} 6 | # h.slice(:a) #=> {:a=>1} 7 | # 8 | def slice(*keep_keys) 9 | if block_given? 10 | each do |k, v| 11 | keep_keys << k if yield(k, v) 12 | end 13 | end 14 | 15 | hash = {} 16 | keep_keys.each do |key| 17 | hash[key] = fetch(key) 18 | end 19 | hash 20 | end 21 | 22 | # Replaces hash with a new hash having only the given keys. 23 | # This return the hash of keys removed. 24 | # 25 | # h = {:a=>1, :b=>2} 26 | # h.slice!(:a) #=> {:b=>2} 27 | # h #=> {:a=>1} 28 | # 29 | # Returns a Hash of the removed pairs. 30 | def slice!(*keep_keys) 31 | if block_given? 32 | each do |k, v| 33 | keep_keys << k if yield(k, v) 34 | end 35 | end 36 | 37 | rejected = keys - keep_keys 38 | removed = {} 39 | rejected.each{ |k| removed[k] = delete(k) } 40 | removed 41 | end 42 | 43 | end 44 | 45 | # NOTE: ActiveSupport defines this method but adds a check for #convert_key. 46 | # If the method is defined, then it converts the keys with it. However 47 | # it doesn't look to be supported by all Hash methods, just 48 | # HashWithIndifferentAccess. I'm not so sure support for this kind of 49 | # thing is appropriate for Facets. 50 | 51 | -------------------------------------------------------------------------------- /work/step/README: -------------------------------------------------------------------------------- 1 | = step 1.0 -- Stepchildren 2 | 3 | Some simple Ruby extensions. 4 | 5 | == Description 6 | 7 | These are methods on standard classes that didn't manage to become part of 8 | the Ruby interpreter. (Although, some are part of Ruby 1.9/1.8.7 but not 9 | 1.8.6). 10 | 11 | They are all very small, most of them have less than 15 lines of code. 12 | So they would not be a weight in the Ruby interpreter but it is very 13 | difficult to convince a majority that they belong there. 14 | 15 | The methods won't be useful for everybody but some programmers may like 16 | to make them part of their programming style. 17 | 18 | If you like to get taunted, then go to the Ruby mailing list and propose 19 | one of them to be included into the Ruby standard. 20 | 21 | == Intention 22 | 23 | In my own code I use quite often a method String#notempty? 24 | that does almost the same as Numeric#nonzero?. Every 25 | attempt proposing it for the Ruby standard implementation has failed; 26 | the discussion evolves the same every time. 27 | 28 | Now here it is where I can just point to it. 29 | 30 | == Contents (uncomplete) 31 | 32 | * String#notempty? 33 | * String#clear 34 | * String#head 35 | * String#tail 36 | * String#rest 37 | * String#starts_with 38 | * String#ends_with 39 | * Array#notempty? 40 | * Hash#notempty? 41 | * Struct.[] 42 | * Interval timer 43 | * File system stats 44 | 45 | -------------------------------------------------------------------------------- /site/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Carats 4 | 16 | 17 | 18 |
19 |

Carats Carrots!

20 |

Ruby Facets in C

21 |
22 |

We need your help!

23 |

We need coders who can translate Ruby source code into C extensions. 24 |

We don't have lots of treasure. But we have plenty of free carrots!

25 | 26 |

Get me some carrots...

27 |
28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 | 36 | 37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /work/step/LICENSE: -------------------------------------------------------------------------------- 1 | _ 2 | ___| |_ ___ _ __ 3 | / __| __/ _ \ '_ \ 4 | \__ \ || __/ |_) | 5 | |___/\__\___| .__/ 6 | |_| 7 | 8 | 9 | Copyright (c) 2009, Bertram Scharpf . 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are 14 | met: 15 | 16 | * Redistributions of source code must retain the above copyright 17 | notice, this list of conditions and the following disclaimer. 18 | 19 | * Redistributions in binary form must reproduce the above copyright 20 | notice, this list of conditions and the following disclaimer in 21 | the documentation and/or other materials provided with the 22 | distribution. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Carats 2 | 3 | [Website](http://rubyworks.github.com/carats) / 4 | [Report Issue](http://github.com/rubyworks/carats/issues) / 5 | [Source Code](http://github.com/rubyworks/carats) 6 | 7 | 8 | ## About 9 | 10 | Carats are Facets written in C. This library is intended to be small 11 | and focused on a few areas where having widely useful extensions 12 | or additions to Ruby could greatly benefit from the speed boost 13 | and/or to access the underbelly of Ruby itself. 14 | 15 | Carats is a work in progress and is currently looking for contributors. 16 | If you are a C and Ruby coder and would like to practice your craft 17 | a bit this a great project to contribute to since all the work is in 18 | very managable "bite-sized" pieces. Contributors are free to select 19 | from Facets as they like. Or even make a case for extensions that are 20 | not yet in Facets. 21 | 22 | ## Bounties! 23 | 24 | To encourge contribution, some bounties will be offered. These are small 25 | figure bounties, so don't expect to get rich off of them, but if a few 26 | greenbacks can help motivate, so much the better. 27 | 28 | Check out the [BOUNTIES](https://github.com/rubyworks/carats/wiki/Bounties) 29 | page for recommended extensions and the rewards offered for their completion. 30 | 31 | 32 | ## Reference 33 | 34 | * [Ruby to C, a couple snippets](http://macournoyer.wordpress.com/2008/04/16/ruby-to-c-a-couple-snippets) 35 | 36 | 37 | ## Copyrights 38 | 39 | Carats (per collection) (c) 2009 Rubyworks 40 | 41 | See NOTICE.md for complete list of copyright notices. 42 | 43 | Carats is distributed under that same licensing terms as Ruby (BSD-2-Clause). 44 | -------------------------------------------------------------------------------- /work/step/step.gemspec: -------------------------------------------------------------------------------- 1 | --- !ruby/object:Gem::Specification 2 | name: step 3 | version: !ruby/object:Gem::Version 4 | version: "1.0" 5 | platform: ruby 6 | authors: 7 | - Bertram Scharpf 8 | autorequire: 9 | bindir: bin 10 | cert_chain: [] 11 | 12 | date: 2009-11-12 00:00:00 +01:00 13 | default_executable: 14 | dependencies: 15 | - !ruby/object:Gem::Dependency 16 | name: autorake 17 | type: :runtime 18 | version_requirement: 19 | version_requirements: !ruby/object:Gem::Requirement 20 | requirements: 21 | - - ">=" 22 | - !ruby/object:Gem::Version 23 | version: "1.0" 24 | version: 25 | description: | 26 | Simple methods that didn_t manage to become part of standard Ruby. 27 | 28 | email: 29 | executables: [] 30 | 31 | extensions: 32 | - lib/mkrf_conf 33 | extra_rdoc_files: 34 | - README 35 | - LICENSE 36 | files: 37 | - lib/mkrf_conf 38 | - lib/Rakefile 39 | - lib/step.c 40 | - lib/step.h 41 | - lib/step/filesys.c 42 | - lib/step/filesys.h 43 | - lib/step/itimer.c 44 | - lib/step/itimer.h 45 | - README 46 | - LICENSE 47 | has_rdoc: true 48 | homepage: http://www.bertram-scharpf.de 49 | licenses: [] 50 | 51 | post_install_message: 52 | rdoc_options: [] 53 | 54 | require_paths: 55 | - lib 56 | required_ruby_version: !ruby/object:Gem::Requirement 57 | requirements: 58 | - - ">=" 59 | - !ruby/object:Gem::Version 60 | version: "0" 61 | version: 62 | required_rubygems_version: !ruby/object:Gem::Requirement 63 | requirements: 64 | - - ">=" 65 | - !ruby/object:Gem::Version 66 | version: "0" 67 | version: 68 | requirements: 69 | - just Ruby 70 | rubyforge_project: step 71 | rubygems_version: 1.3.5 72 | signing_key: 73 | specification_version: 3 74 | summary: Simple Ruby extensions 75 | test_files: [] 76 | 77 | -------------------------------------------------------------------------------- /ext/string/margin/margin.rb: -------------------------------------------------------------------------------- 1 | require 'facets/string/indent' 2 | 3 | class String 4 | 5 | # Preserve relative tabbing such that the line with the least amount 6 | # of white space ends up with the given number of spaces before non-space 7 | # and all other lines move relative to it. 8 | # 9 | # Because of the nature of this method leading tab characters (`\t`) must 10 | # be converted to spaces. The size of a tab can be set via the `:tab` option. 11 | # The default size is 2. 12 | # 13 | # If the `:lead` option is set, then the relative margin is determined 14 | # by the first non-blank line, instead of the minimum white-space for all 15 | # lines. 16 | # 17 | # Arguments 18 | # 19 | # num - The size of the desired margin. [Integer] 20 | # opts - Margin options. [Hash] 21 | # 22 | # Options 23 | # 24 | # :tab - Size of tab character in spaces. [Integer] 25 | # :lead - Use first non-blank line as relative marker. [Boolean] 26 | # 27 | # Returns a new String with adjusted margin. [String] 28 | # 29 | # Author: Gavin Sinclair 30 | # Author: Trans 31 | 32 | def margin(num=nil, opts={}) 33 | # TODO: temporary to help people transition 34 | raise ArgumentError, "String#margin has been renamed to #trim." 35 | 36 | tab = opts[:tab] || 2 37 | str = gsub("\t", " " * tab) # TODO: only leading tabs ? 38 | 39 | if opts[:lead] 40 | if self =~ /^( *)\S/ 41 | indent(num - $1.length) 42 | else 43 | self 44 | end 45 | else 46 | min = [] 47 | str.each_line do |line| 48 | next if line.strip.empty? 49 | min << line.index(/\S/) 50 | end 51 | min = min.min 52 | str.indent(num - min) 53 | end 54 | end 55 | 56 | # Original name of #margin. 57 | alias :tabto :margin 58 | 59 | end 60 | -------------------------------------------------------------------------------- /ext/string/indent/indent.rb: -------------------------------------------------------------------------------- 1 | class String 2 | 3 | # Indent left or right by `n` spaces, or `n` number of `c` string. 4 | # 5 | # n - the number of spaces to indent 6 | # c - character to use, if other then space 7 | # 8 | # Returns a new string with the indention. [String] 9 | # 10 | # Author: Gavin Sinclair 11 | # Author: Trans 12 | # Author: Tyler Rick 13 | 14 | def indent(n, c=' ') 15 | if n >= 0 16 | gsub(/^/, c * n) 17 | else 18 | gsub(/^#{Regexp.escape(c)}{0,#{-n}}/, "") 19 | end 20 | end 21 | 22 | # Equivalent to String#indent, but modifies the receiver in place. 23 | # 24 | # Returns this string indented. [String] 25 | 26 | def indent!(n, c=' ') 27 | replace(indent(n,c)) 28 | end 29 | 30 | # Remove excessive indentation. Useful for multi-line strings embeded in 31 | # already indented code. 32 | # 33 | # Examples 34 | # 35 | # <<-END.unindent 36 | # ohaie 37 | # wurld 38 | # END 39 | # #=> "ohaie\n wurld" 40 | # 41 | # Returns a new string with the unindention. [String] 42 | # 43 | # Author: Noah Gibbs 44 | # Author: mynyml 45 | 46 | def unindent(size=nil) 47 | if size 48 | indent(-size) 49 | else 50 | char = ' ' 51 | self.scan(/^[\ \t]*\S/) do |m| 52 | if size.nil? || m.size < size 53 | size = m.size 54 | char = m[0...-1] 55 | end 56 | end 57 | size -= 1 58 | indent(-size, char) 59 | end 60 | end 61 | 62 | # Equivalent to String#unindent, but modifies the receiver in place. 63 | # 64 | # Returns this string unindented. [String] 65 | # 66 | # Author: mynyml 67 | 68 | def unindent! 69 | replace(unindent) 70 | end 71 | 72 | alias :tab :indent 73 | alias :tab! :indent! 74 | 75 | alias :backtab :unindent 76 | alias :backtab! :unindent! 77 | 78 | end 79 | -------------------------------------------------------------------------------- /ext/hash/rekey/rekey.rb: -------------------------------------------------------------------------------- 1 | require 'facets/symbol/to_proc' 2 | require 'facets/na' 3 | 4 | class Hash 5 | 6 | # TODO: Improve Hash#rekey code!!! 7 | 8 | # Rekey a hash: 9 | # 10 | # rekey() 11 | # rekey(from_key => to_key, ...) 12 | # rekey{|from_key| to_key} 13 | # 14 | # If a key map is given, then the first key is changed to the second key. 15 | # 16 | # foo = { :a=>1, :b=>2 } 17 | # foo.rekey(:a=>'a') #=> { 'a'=>1, :b=>2 } 18 | # foo.rekey(:b=>:x) #=> { :a =>1, :x=>2 } 19 | # foo.rekey('foo'=>'bar') #=> { :a =>1, :b=>2 } 20 | # 21 | # If a block is given, converts all keys in the Hash accroding to the 22 | # given block procedure. If the block returns +NA+ for a given key, 23 | # then that key will be left intact. 24 | # 25 | # foo = { :name=>'Gavin', :wife=>:Lisa } 26 | # foo.rekey{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa } 27 | # foo #=> { :name =>"Gavin", :wife=>:Lisa } 28 | # 29 | # If no key map or block is given, then all keys are converted 30 | # to Symbols. 31 | # 32 | # Note that if both a +key_map+ and a block are given, the +key_map+ is 33 | # applied first then the block. 34 | # 35 | # CREDIT: Trans, Gavin Kistner 36 | 37 | def rekey(key_map=nil, &block) 38 | if !(key_map or block) 39 | block = lambda{|k| k.to_sym} 40 | end 41 | 42 | key_map ||= {} 43 | 44 | hash = dup.replace({}) # to keep default_proc 45 | 46 | (keys - key_map.keys).each do |key| 47 | hash[key] = self[key] 48 | end 49 | 50 | key_map.each do |from, to| 51 | hash[to] = self[from] if key?(from) 52 | end 53 | 54 | if block 55 | hash2 = dup.replace({}) 56 | case block.arity 57 | when 2 # TODO: is this condition needed? 58 | hash.each do |k, v| 59 | nk = block.call(k,v) 60 | nk = (NA == nk ? k : nk) 61 | hash2[nk] = v 62 | end 63 | else 64 | hash.each do |k, v| 65 | nk = block.call(k) 66 | nk = (NA == nk ? k : nk) 67 | hash2[nk] = v 68 | end 69 | end 70 | else 71 | hash2 = hash 72 | end 73 | 74 | hash2 75 | end 76 | 77 | # Synonym for Hash#rekey, but modifies the receiver in place (and returns it). 78 | # 79 | # foo = { :name=>'Gavin', :wife=>:Lisa } 80 | # foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa } 81 | # foo #=> { "name"=>"Gavin", "wife"=>:Lisa } 82 | # 83 | # CREDIT: Trans, Gavin Kistner 84 | 85 | def rekey!(key_map=nil, &block) 86 | replace(rekey(key_map, &block)) 87 | end 88 | 89 | end 90 | -------------------------------------------------------------------------------- /work/step/lib/step/itimer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * itimer.c -- Interval timer 3 | */ 4 | 5 | 6 | #include "itimer.h" 7 | 8 | #include 9 | 10 | static void step_sec_timeval( VALUE, struct timeval *t); 11 | static VALUE step_timeval_sec( struct timeval *); 12 | 13 | 14 | /* 15 | * call-seq: 16 | * Process.setitimer( interval = nil, value = nil) -> nil 17 | * 18 | * Set alarm timer. If value is nonzero, it is the 19 | * expiration time to the first alarm. If it is zero, the timer is disabled. 20 | * If value is nonzero and interval is zero, 21 | * the alarm is triggered once. 22 | * 23 | */ 24 | 25 | VALUE 26 | rb_process_setitimer( int argc, VALUE *argv, VALUE obj) 27 | { 28 | VALUE isec; 29 | VALUE vsec; 30 | struct itimerval it; 31 | 32 | rb_scan_args( argc, argv, "02", &isec, &vsec); 33 | 34 | step_sec_timeval( isec, &it.it_interval); 35 | if (NIL_P(vsec) && !NIL_P(isec)) 36 | it.it_value = it.it_interval; 37 | else 38 | step_sec_timeval( vsec, &it.it_value); 39 | 40 | if (setitimer( ITIMER_REAL, &it, NULL) < 0) 41 | rb_raise( rb_eSystemCallError, "setitimer failed."); 42 | return Qnil; 43 | } 44 | 45 | void 46 | step_sec_timeval( VALUE secs, struct timeval *t) 47 | { 48 | switch (TYPE(secs)) { 49 | case T_FIXNUM: 50 | t->tv_sec = FIX2LONG(secs), t->tv_usec = 0; 51 | if (t->tv_sec < 0) 52 | rb_raise( rb_eArgError, "time interval must be positive"); 53 | break; 54 | 55 | case T_FLOAT: 56 | if (RFLOAT(secs)->value < 0.0) 57 | rb_raise( rb_eArgError, "time interval must be positive"); 58 | else { 59 | double f, d; 60 | 61 | d = modf( RFLOAT(secs)->value, &f); 62 | t->tv_sec = (time_t) f, t->tv_usec = (time_t) (d*1e6+0.5); 63 | if (f != t->tv_sec) 64 | rb_raise( rb_eRangeError, "time interval out of Time range", 65 | RFLOAT(secs)->value); 66 | } 67 | break; 68 | 69 | case T_BIGNUM: 70 | t->tv_sec = NUM2LONG(secs), t->tv_usec = 0; 71 | if (t->tv_sec < 0) 72 | rb_raise(rb_eArgError, "time interval must be positive"); 73 | break; 74 | 75 | case T_NIL: 76 | t->tv_sec = 0, t->tv_usec = 0; 77 | break; 78 | 79 | default: 80 | rb_raise( rb_eTypeError, "can't convert %s into time interval", 81 | rb_obj_classname( secs)); 82 | break; 83 | } 84 | } 85 | 86 | 87 | /* 88 | * call-seq: 89 | * Process.getitimer -> [interval, value] 90 | * 91 | * Returns the interval and the remaining seconds to next alarm. 92 | */ 93 | 94 | VALUE 95 | rb_process_getitimer( VALUE obj) 96 | { 97 | struct itimerval it; 98 | VALUE r; 99 | 100 | if (getitimer( ITIMER_REAL, &it) < 0) 101 | rb_raise( rb_eSystemCallError, "getitimer failed."); 102 | 103 | r = rb_ary_new2( 2); 104 | RARRAY( r)->len = 2; 105 | rb_ary_store( r, 0, step_timeval_sec( &it.it_interval)); 106 | rb_ary_store( r, 1, step_timeval_sec( &it.it_value)); 107 | return r; 108 | } 109 | 110 | VALUE 111 | step_timeval_sec( struct timeval *t) 112 | { 113 | VALUE r; 114 | if (t->tv_usec) 115 | r = rb_float_new( t->tv_sec + (1e-6 * t->tv_usec)); 116 | else 117 | r = INT2NUM(t->tv_sec); 118 | return r; 119 | } 120 | 121 | 122 | void Init_itimer( void) 123 | { 124 | rb_define_singleton_method( rb_mProcess, "setitimer", rb_process_setitimer, -1); 125 | rb_define_singleton_method( rb_mProcess, "getitimer", rb_process_getitimer, 0); 126 | } 127 | 128 | -------------------------------------------------------------------------------- /work/parse.y.yaml.patch: -------------------------------------------------------------------------------- 1 | *** parse.y.1.9.3-p0 2011-11-12 15:42:07.000000000 +0900 2 | --- parse.y 2011-11-12 15:41:18.000000000 +0900 3 | *************** 4 | *** 682,688 **** 5 | --- 682,690 ---- 6 | %token tREGEXP_END 7 | 8 | %type singleton strings string string1 xstring regexp 9 | + %type yaml 10 | %type string_contents xstring_contents regexp_contents string_content 11 | + %type yaml_contents 12 | %type words qwords word_list qword_list word 13 | %type literal numeric dsym cpath 14 | %type top_compstmt top_stmts top_stmt 15 | *************** 16 | *** 735,740 **** 17 | --- 737,743 ---- 18 | %token tAMPER /* & */ 19 | %token tLAMBDA /* -> */ 20 | %token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG 21 | + %token tYAML_BEG 22 | %token tSTRING_DBEG tSTRING_DVAR tSTRING_END tLAMBEG 23 | 24 | /* 25 | *************** 26 | *** 2616,2621 **** 27 | --- 2619,2625 ---- 28 | primary : literal 29 | | strings 30 | | xstring 31 | + | yaml 32 | | regexp 33 | | words 34 | | qwords 35 | *************** 36 | *** 3905,3910 **** 37 | --- 3909,3926 ---- 38 | } 39 | ; 40 | 41 | + yaml : tYAML_BEG yaml_contents tSTRING_END 42 | + { 43 | + /*%%%*/ 44 | + NODE *node = $2; 45 | + if (!node) node = NEW_STR(STR_NEW0()); 46 | + $$ = NEW_CALL(node, rb_intern("__yaml__"), 0) 47 | + /*% 48 | + $$ = dispatch1(xstring_literal, $2); 49 | + %*/ 50 | + } 51 | + ; 52 | + 53 | regexp : tREGEXP_BEG regexp_contents tREGEXP_END 54 | { 55 | /*%%%*/ 56 | *************** 57 | *** 4098,4103 **** 58 | --- 4114,4137 ---- 59 | } 60 | ; 61 | 62 | + yaml_contents : /* none */ 63 | + { 64 | + /*%%%*/ 65 | + $$ = 0; 66 | + /*% 67 | + $$ = dispatch0(xstring_new); 68 | + %*/ 69 | + } 70 | + | yaml_contents string_content 71 | + { 72 | + /*%%%*/ 73 | + $$ = literal_concat($1, $2); 74 | + /*% 75 | + $$ = dispatch2(xstring_add, $1, $2); 76 | + %*/ 77 | + } 78 | + ; 79 | + 80 | regexp_contents: /* none */ 81 | { 82 | /*%%%*/ 83 | *************** 84 | *** 5383,5388 **** 85 | --- 5417,5423 ---- 86 | #define STR_FUNC_QWORDS 0x08 87 | #define STR_FUNC_SYMBOL 0x10 88 | #define STR_FUNC_INDENT 0x20 89 | + #define STR_FUNC_YAML 0x40 90 | 91 | enum string_type { 92 | str_squote = (0), 93 | *************** 94 | *** 5392,5398 **** 95 | str_sword = (STR_FUNC_QWORDS), 96 | str_dword = (STR_FUNC_QWORDS|STR_FUNC_EXPAND), 97 | str_ssym = (STR_FUNC_SYMBOL), 98 | ! str_dsym = (STR_FUNC_SYMBOL|STR_FUNC_EXPAND) 99 | }; 100 | 101 | static VALUE 102 | --- 5427,5434 ---- 103 | str_sword = (STR_FUNC_QWORDS), 104 | str_dword = (STR_FUNC_QWORDS|STR_FUNC_EXPAND), 105 | str_ssym = (STR_FUNC_SYMBOL), 106 | ! str_dsym = (STR_FUNC_SYMBOL|STR_FUNC_EXPAND), 107 | ! str_yaml = (STR_FUNC_YAML|STR_FUNC_EXPAND) 108 | }; 109 | 110 | static VALUE 111 | *************** 112 | *** 5859,5864 **** 113 | --- 5895,5901 ---- 114 | rb_encoding *enc = *encp; 115 | char *errbuf = 0; 116 | static const char mixed_msg[] = "%s mixed within %s source"; 117 | + int yaml_dotlen = 0; 118 | 119 | #define mixed_error(enc1, enc2) if (!errbuf) { \ 120 | size_t len = sizeof(mixed_msg) - 4; \ 121 | *************** 122 | *** 5878,5883 **** 123 | --- 5915,5932 ---- 124 | } while (0) 125 | 126 | while ((c = nextc()) != -1) { 127 | + if (func == str_yaml) { 128 | + if (c == '.') { 129 | + yaml_dotlen++; 130 | + if (yaml_dotlen == 3) { 131 | + //return -1; 132 | + return 1; 133 | + } 134 | + } 135 | + else { 136 | + yaml_dotlen = 0; 137 | + } 138 | + } 139 | if (paren && c == paren) { 140 | ++*nest; 141 | } 142 | *************** 143 | *** 6037,6042 **** 144 | --- 6086,6094 ---- 145 | 146 | tokfix(); 147 | set_yylval_str(STR_NEW3(tok(), toklen(), enc, func)); 148 | + if (func == str_yaml) { 149 | + quote->nd_func = -1; 150 | + } 151 | 152 | #ifdef RIPPER 153 | if (!NIL_P(parser->delayed)) { 154 | *************** 155 | *** 6048,6054 **** 156 | parser->tokp = lex_p; 157 | } 158 | #endif 159 | ! 160 | return tSTRING_CONTENT; 161 | } 162 | 163 | --- 6100,6106 ---- 164 | parser->tokp = lex_p; 165 | } 166 | #endif 167 | ! 168 | return tSTRING_CONTENT; 169 | } 170 | 171 | *************** 172 | *** 7135,7140 **** 173 | --- 7187,7200 ---- 174 | lex_state = EXPR_ARG; 175 | return tLAMBDA; 176 | } 177 | + if (c == '-') { 178 | + c = nextc(); 179 | + if (c == '-') { 180 | + lex_strterm = NEW_STRTERM(str_yaml, c, 0); 181 | + return tYAML_BEG; 182 | + } 183 | + pushback('-'); 184 | + } 185 | if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous())) { 186 | lex_state = EXPR_BEG; 187 | pushback(c); 188 | -------------------------------------------------------------------------------- /.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'yaml' 4 | 5 | module DotRuby 6 | 7 | # 8 | class GemSpec 9 | 10 | # For which revision of .ruby is this gemspec intended? 11 | REVISION = 0 unless defined?(REVISION) 12 | 13 | # 14 | PATTERNS = { 15 | :bin_files => 'bin/*', 16 | :lib_files => 'lib/{**/}*.rb', 17 | :ext_files => 'ext/{**/}extconf.rb', 18 | :doc_files => '*.{txt,rdoc,md,markdown,tt,textile}', 19 | :test_files => '{test/{**/}*_test.rb,spec/{**/}*_spec.rb}' 20 | } unless defined?(PATTERNS) 21 | 22 | # 23 | def self.instance 24 | new.to_gemspec 25 | end 26 | 27 | attr :metadata 28 | 29 | attr :manifest 30 | 31 | # 32 | def initialize 33 | @metadata = YAML.load_file('.ruby') 34 | @manifest = Dir.glob('manifest{,.txt}', File::FNM_CASEFOLD).first 35 | 36 | if @metadata['revision'].to_i != REVISION 37 | warn "You have the wrong revision. Trying anyway..." 38 | end 39 | end 40 | 41 | # 42 | def scm 43 | @scm ||= \ 44 | case 45 | when File.directory?('.git') 46 | :git 47 | end 48 | end 49 | 50 | # 51 | def files 52 | @files ||= \ 53 | #glob_files[patterns[:files]] 54 | case 55 | when manifest 56 | File.readlines(manifest). 57 | map{ |line| line.strip }. 58 | reject{ |line| line.empty? || line[0,1] == '#' } 59 | when scm == :git 60 | `git ls-files -z`.split("\0") 61 | else 62 | Dir.glob('{**/}{.*,*}') # TODO: be more specific using standard locations ? 63 | end.select{ |path| File.file?(path) } 64 | end 65 | 66 | # 67 | def glob_files(pattern) 68 | Dir.glob(pattern).select { |path| 69 | File.file?(path) && files.include?(path) 70 | } 71 | end 72 | 73 | # 74 | def patterns 75 | PATTERNS 76 | end 77 | 78 | # 79 | def executables 80 | @executables ||= \ 81 | glob_files(patterns[:bin_files]).map do |path| 82 | File.basename(path) 83 | end 84 | end 85 | 86 | def extensions 87 | @extensions ||= \ 88 | glob_files(patterns[:ext_files]).map do |path| 89 | File.basename(path) 90 | end 91 | end 92 | 93 | # 94 | def name 95 | metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_') 96 | end 97 | 98 | # 99 | def to_gemspec 100 | Gem::Specification.new do |gemspec| 101 | gemspec.name = name 102 | gemspec.version = metadata['version'] 103 | gemspec.summary = metadata['summary'] 104 | gemspec.description = metadata['description'] 105 | 106 | metadata['authors'].each do |author| 107 | gemspec.authors << author['name'] 108 | 109 | if author.has_key?('email') 110 | if gemspec.email 111 | gemspec.email << author['email'] 112 | else 113 | gemspec.email = [author['email']] 114 | end 115 | end 116 | end 117 | 118 | gemspec.licenses = metadata['copyrights'].map{ |c| c['license'] }.compact 119 | 120 | metadata['requirements'].each do |req| 121 | name = req['name'] 122 | version = req['version'] 123 | groups = req['groups'] || [] 124 | 125 | case version 126 | when /^(.*?)\+$/ 127 | version = ">= #{$1}" 128 | when /^(.*?)\-$/ 129 | version = "< #{$1}" 130 | when /^(.*?)\~$/ 131 | version = "~> #{$1}" 132 | end 133 | 134 | if groups.empty? or groups.include?('runtime') 135 | # populate runtime dependencies 136 | if gemspec.respond_to?(:add_runtime_dependency) 137 | gemspec.add_runtime_dependency(name,*version) 138 | else 139 | gemspec.add_dependency(name,*version) 140 | end 141 | else 142 | # populate development dependencies 143 | if gemspec.respond_to?(:add_development_dependency) 144 | gemspec.add_development_dependency(name,*version) 145 | else 146 | gemspec.add_dependency(name,*version) 147 | end 148 | end 149 | end 150 | 151 | # convert external dependencies into a requirements 152 | if metadata['external_dependencies'] 153 | ##gemspec.requirements = [] unless metadata['external_dependencies'].empty? 154 | metadata['external_dependencies'].each do |req| 155 | gemspec.requirements << req.to_s 156 | end 157 | end 158 | 159 | # determine homepage from resources 160 | homepage = metadata['resources'].find{ |key, url| key =~ /^home/ } 161 | gemspec.homepage = homepage.last if homepage 162 | 163 | gemspec.require_paths = metadata['load_path'] || ['lib'] 164 | gemspec.post_install_message = metadata['install_message'] 165 | 166 | # RubyGems specific metadata 167 | gemspec.files = files 168 | gemspec.extensions = extensions 169 | gemspec.executables = executables 170 | 171 | if Gem::VERSION < '1.7.' 172 | gemspec.default_executable = gemspec.executables.first 173 | end 174 | 175 | gemspec.test_files = glob_files(patterns[:test_files]) 176 | 177 | unless gemspec.files.include?('.document') 178 | gemspec.extra_rdoc_files = glob_files(patterns[:doc_files]) 179 | end 180 | end 181 | end 182 | 183 | end #class GemSpec 184 | 185 | end 186 | 187 | DotRuby::GemSpec.instance 188 | -------------------------------------------------------------------------------- /work/step/lib/step/filesys.c: -------------------------------------------------------------------------------- 1 | /* 2 | * filesys.c -- File system tools 3 | */ 4 | 5 | #include "filesys.h" 6 | 7 | #include 8 | #ifdef __FSID_T_TYPE 9 | /* Linux */ 10 | #include 11 | #else 12 | #include 13 | #include 14 | #endif 15 | 16 | 17 | 18 | static struct statfs *get_statfs( VALUE); 19 | 20 | static ID id_mul; 21 | 22 | /* 23 | * Document-class: Filesys 24 | * 25 | * File systems. Mount and umount commands are on the TODO list. 26 | */ 27 | 28 | /* 29 | * Document-class: Filesys::Stat 30 | * 31 | * Objects of class Filesys::Stat encapsulate common status 32 | * information for Filesys objects. The information is 33 | * recorded at the moment the Filesys::Stat object is 34 | * created; changes made to the file after that point will not be 35 | * reflected. 36 | * 37 | * Many of its attributes contain platform-specific values, and not all 38 | * values are meaningful on all systems. 39 | */ 40 | 41 | VALUE 42 | rb_fsstat_s_alloc( VALUE klass) 43 | { 44 | return Data_Wrap_Struct( klass, NULL, &free, (struct statfs *) NULL); 45 | } 46 | 47 | /* 48 | * call-seq: 49 | * 50 | * Filesys::Stat.new( dir_name) => stat 51 | * 52 | * Create a Filesys::Stat object for the given file system. 53 | */ 54 | 55 | VALUE 56 | rb_fsstat_init( VALUE obj, VALUE dname) 57 | { 58 | struct statfs st, *nst; 59 | 60 | SafeStringValue( dname); 61 | 62 | if (statfs( StringValueCStr( dname), &st) == -1) 63 | rb_sys_fail( RSTRING(dname)->ptr); 64 | if (DATA_PTR(obj)) { 65 | free( DATA_PTR(obj)); 66 | DATA_PTR(obj) = NULL; 67 | } 68 | nst = ALLOC(struct statfs); 69 | *nst = st; 70 | DATA_PTR(obj) = nst; 71 | 72 | return Qnil; 73 | } 74 | 75 | /* :nodoc: */ 76 | VALUE 77 | rb_fsstat_init_copy( VALUE copy, VALUE orig) 78 | { 79 | struct statfs *nst; 80 | 81 | if (copy == orig) 82 | return orig; 83 | 84 | rb_check_frozen( copy); 85 | if (!rb_obj_is_instance_of( orig, rb_obj_class( copy))) 86 | rb_raise(rb_eTypeError, "wrong argument class"); 87 | if (DATA_PTR(copy)) { 88 | free( DATA_PTR(copy)); 89 | DATA_PTR(copy) = NULL; 90 | } 91 | if (DATA_PTR(orig)) { 92 | nst = ALLOC(struct statfs); 93 | *nst = *(struct statfs *) DATA_PTR(orig); 94 | DATA_PTR(copy) = nst; 95 | } 96 | 97 | return copy; 98 | } 99 | 100 | /* :nodoc: */ 101 | struct statfs * 102 | get_statfs( VALUE self) 103 | { 104 | struct statfs *st; 105 | Data_Get_Struct(self, struct statfs, st); 106 | if (!st) 107 | rb_raise( rb_eTypeError, "uninitialized Filesys::Stat"); 108 | return st; 109 | } 110 | 111 | 112 | 113 | /* 114 | * call-seq: 115 | * stat.type => fixnum 116 | * 117 | * Type of filesystem. 118 | */ 119 | 120 | VALUE 121 | rb_fsstat_type( VALUE self) 122 | { 123 | return INT2NUM(get_statfs(self)->f_type); 124 | } 125 | 126 | /* 127 | * call-seq: 128 | * stat.bsize => fixnum 129 | * 130 | * Filesystem fragment size. 131 | */ 132 | 133 | VALUE 134 | rb_fsstat_bsize( VALUE self) 135 | { 136 | return INT2NUM(get_statfs(self)->f_bsize); 137 | } 138 | 139 | /* 140 | * call-seq: 141 | * stat.blocks => fixnum 142 | * 143 | * Total data blocks in filesystem. 144 | */ 145 | 146 | VALUE 147 | rb_fsstat_blocks( VALUE self) 148 | { 149 | return INT2NUM(get_statfs(self)->f_blocks); 150 | } 151 | 152 | /* 153 | * call-seq: 154 | * stat.bfree => fixnum 155 | * 156 | * Free blocks in filesystem. 157 | */ 158 | 159 | VALUE 160 | rb_fsstat_bfree( VALUE self) 161 | { 162 | return INT2NUM(get_statfs(self)->f_bfree); 163 | } 164 | 165 | /* 166 | * call-seq: 167 | * stat.bavail => fixnum 168 | * 169 | * Free blocks avail to non-superuser. 170 | */ 171 | 172 | VALUE 173 | rb_fsstat_bavail( VALUE self) 174 | { 175 | return INT2NUM(get_statfs(self)->f_bavail); 176 | } 177 | 178 | /* 179 | * call-seq: 180 | * stat.files => fixnum 181 | * 182 | * Total file nodes in filesystem. 183 | */ 184 | 185 | VALUE 186 | rb_fsstat_files( VALUE self) 187 | { 188 | return INT2NUM(get_statfs(self)->f_files); 189 | } 190 | 191 | /* 192 | * call-seq: 193 | * stat.ffree => fixnum 194 | * 195 | * Free nodes avail to non-superuser. 196 | */ 197 | 198 | VALUE 199 | rb_fsstat_ffree( VALUE self) 200 | { 201 | return INT2NUM(get_statfs(self)->f_ffree); 202 | } 203 | 204 | 205 | /* 206 | * call-seq: 207 | * stat.fsid => fixnum 208 | * 209 | * Filesystem id. 210 | */ 211 | 212 | #ifdef __FSID_T_TYPE 213 | /* Linux */ 214 | #define FSID_val __val 215 | #else 216 | #define FSID_val val 217 | #endif 218 | 219 | VALUE 220 | rb_fsstat_fsid( VALUE self) 221 | { 222 | struct statfs *s; 223 | VALUE r; 224 | int i; 225 | 226 | s = get_statfs( self); 227 | i = 2; 228 | r = rb_ary_new2( i); 229 | RARRAY( r)->len = i; 230 | while (i > 0) { 231 | --i; 232 | rb_ary_store( r, i, INT2NUM(s->f_fsid.FSID_val[i])); 233 | } 234 | return r; 235 | } 236 | 237 | 238 | /* 239 | * call-seq: 240 | * stat.bytes => fixnum 241 | * 242 | * Total data bytes in filesystem. 243 | */ 244 | 245 | VALUE 246 | rb_fsstat_bytes( VALUE self) 247 | { 248 | struct statfs *s; 249 | 250 | s = get_statfs( self); 251 | return rb_funcall( INT2NUM(s->f_blocks), id_mul, 1, INT2NUM(s->f_bsize)); 252 | } 253 | 254 | /* 255 | * call-seq: 256 | * stat.free => num 257 | * 258 | * Free bytes in filesystem. 259 | */ 260 | 261 | VALUE 262 | rb_fsstat_free( VALUE self) 263 | { 264 | struct statfs *s; 265 | 266 | s = get_statfs( self); 267 | return rb_funcall( INT2NUM(s->f_bfree), id_mul, 1, INT2NUM(s->f_bsize)); 268 | } 269 | 270 | /* 271 | * call-seq: 272 | * stat.avail => num 273 | * 274 | * Free bytes avail to non-superuser. 275 | */ 276 | 277 | VALUE 278 | rb_fsstat_avail( VALUE self) 279 | { 280 | struct statfs *s; 281 | 282 | s = get_statfs( self); 283 | return rb_funcall( INT2NUM(s->f_bavail), id_mul, 1, INT2NUM(s->f_bsize)); 284 | } 285 | 286 | 287 | /* 288 | * call-seq: 289 | * stat.pfree => fixnum 290 | * 291 | * Free percentage in filesystem. 292 | */ 293 | 294 | VALUE 295 | rb_fsstat_pfree( VALUE self) 296 | { 297 | struct statfs *s; 298 | 299 | s = get_statfs( self); 300 | return rb_float_new( 100.0 * s->f_bfree / s->f_blocks); 301 | } 302 | 303 | /* 304 | * call-seq: 305 | * stat.pavail => fixnum 306 | * 307 | * Free percentage avail to non-superuser. 308 | */ 309 | 310 | VALUE 311 | rb_fsstat_pavail( VALUE self) 312 | { 313 | struct statfs *s; 314 | 315 | s = get_statfs( self); 316 | return rb_float_new( 100.0 * s->f_bavail / s->f_blocks); 317 | } 318 | 319 | 320 | /* 321 | * call-seq: 322 | * stat.inspect => string 323 | * 324 | * Produce a nicely formatted description of stat with all available 325 | * information. 326 | */ 327 | 328 | VALUE 329 | rb_fsstat_inspect( VALUE self) 330 | { 331 | VALUE str; 332 | int i, m; 333 | static const struct { 334 | const char *name; 335 | VALUE (*func)(VALUE); 336 | } member[] = { 337 | { "type", &rb_fsstat_type }, 338 | { "bsize", &rb_fsstat_bsize }, 339 | { "blocks", &rb_fsstat_blocks}, 340 | { "bfree", &rb_fsstat_bfree }, 341 | { "bavail", &rb_fsstat_bavail}, 342 | { "files", &rb_fsstat_files }, 343 | { "ffree", &rb_fsstat_ffree }, 344 | { "fsid", &rb_fsstat_fsid } 345 | }; 346 | 347 | str = rb_str_buf_new2("#<"); 348 | rb_str_buf_cat2(str, rb_obj_classname( self)); 349 | rb_str_buf_cat2(str, " "); 350 | 351 | m = sizeof(member) / sizeof(member[0]); 352 | for (i = 0; i < m; i++) { 353 | VALUE v; 354 | 355 | if (i > 0) 356 | rb_str_buf_cat2( str, ", "); 357 | rb_str_buf_cat2( str, member[i].name); 358 | rb_str_buf_cat2( str, "="); 359 | rb_str_append( str, rb_inspect( (*member[i].func)( self))); 360 | } 361 | rb_str_buf_cat2( str, ">"); 362 | OBJ_INFECT( str, self); 363 | 364 | return str; 365 | } 366 | 367 | 368 | 369 | void Init_filesys( void) 370 | { 371 | VALUE rb_cFilesys; 372 | VALUE rb_cFilesysStat; 373 | 374 | rb_cFilesys = rb_define_class( "Filesys", rb_cObject); 375 | 376 | rb_cFilesysStat = rb_define_class_under( rb_cFilesys, "Stat", rb_cObject); 377 | rb_define_alloc_func( rb_cFilesysStat, rb_fsstat_s_alloc); 378 | rb_define_method( rb_cFilesysStat, "initialize", rb_fsstat_init, 1); 379 | rb_define_method( rb_cFilesysStat, "initialize_copy", rb_fsstat_init_copy, 1); 380 | 381 | rb_define_method( rb_cFilesysStat, "type", rb_fsstat_type , 0); 382 | rb_define_method( rb_cFilesysStat, "bsize", rb_fsstat_bsize , 0); 383 | rb_define_method( rb_cFilesysStat, "blocks", rb_fsstat_blocks, 0); 384 | rb_define_method( rb_cFilesysStat, "bfree", rb_fsstat_bfree , 0); 385 | rb_define_method( rb_cFilesysStat, "bavail", rb_fsstat_bavail, 0); 386 | rb_define_method( rb_cFilesysStat, "files", rb_fsstat_files , 0); 387 | rb_define_method( rb_cFilesysStat, "ffree", rb_fsstat_ffree , 0); 388 | rb_define_method( rb_cFilesysStat, "fsid", rb_fsstat_fsid , 0); 389 | 390 | rb_define_method( rb_cFilesysStat, "bytes", rb_fsstat_bytes, 0); 391 | rb_define_method( rb_cFilesysStat, "free", rb_fsstat_free , 0); 392 | rb_define_method( rb_cFilesysStat, "avail", rb_fsstat_avail, 0); 393 | rb_define_method( rb_cFilesysStat, "pfree", rb_fsstat_pfree , 0); 394 | rb_define_method( rb_cFilesysStat, "pavail", rb_fsstat_pavail, 0); 395 | 396 | rb_define_method( rb_cFilesysStat, "inspect", rb_fsstat_inspect, 0); 397 | 398 | id_mul = rb_intern( "*"); 399 | } 400 | 401 | -------------------------------------------------------------------------------- /work/step/lib/step.c: -------------------------------------------------------------------------------- 1 | /* 2 | * step.c -- Simple Ruby Extensions 3 | */ 4 | 5 | #include "step.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | static VALUE step_index_blk( VALUE); 15 | static VALUE step_rindex_blk( VALUE); 16 | #ifdef ARRAY_INDEX_WITH_BLOCK 17 | static VALUE step_index_val( VALUE, VALUE); 18 | static VALUE step_rindex_val( VALUE, VALUE); 19 | #endif 20 | 21 | static ID id_delete_at; 22 | 23 | 24 | #ifdef KERNEL_TAP 25 | 26 | /* 27 | * call-seq: 28 | * obj.tap { |x| ... } -> obj 29 | * 30 | * Yields x to the block, and then returns x. 31 | * The primary purpose of this method is to "tap into" a method chain, 32 | * in order to perform operations on intermediate results within the chain. 33 | * 34 | * (1..10) .tap { |x| puts "original: #{x.inspect}" } 35 | * .to_a .tap { |x| puts "array: #{x.inspect}" } 36 | * .select { |x| x%2==0 } .tap { |x| puts "evens: #{x.inspect}" } 37 | * .map { |x| x*x } .tap { |x| puts "squares: #{x.inspect}" } 38 | * 39 | */ 40 | 41 | VALUE 42 | rb_krn_tap( VALUE obj) 43 | { 44 | rb_yield( obj); 45 | return obj; 46 | } 47 | #endif 48 | 49 | 50 | /* 51 | * call-seq: 52 | * str.notempty? -> nil or self 53 | * 54 | * Returns self if and only if str is not 55 | * empty, nil otherwise. 56 | * 57 | * "hello".notempty? #=> "hello" 58 | * "".notempty? #=> nil 59 | */ 60 | 61 | VALUE 62 | rb_str_notempty( VALUE str) 63 | { 64 | #if 0 65 | /* Ruby Coding style */ 66 | if (RSTRING_LEN(str) == 0) 67 | return Qnil; 68 | return str; 69 | #else 70 | return RSTRING_LEN( str) ? str : Qnil; 71 | #endif 72 | } 73 | 74 | 75 | /* 76 | * call-seq: 77 | * str.eat( n = nil) -> str 78 | * 79 | * Returns first n characters of self or 80 | * whole string if n is nil. The returned 81 | * substring will be deleted from self. If n 82 | * is negative, characters will be eaten from the right. 83 | * 84 | * a = "upcase" 85 | * a.eat 2 #=> "up" 86 | * a #=> "case" 87 | */ 88 | 89 | VALUE 90 | rb_str_eat( int argc, VALUE *argv, VALUE str) 91 | { 92 | VALUE val; 93 | int n; 94 | int l; 95 | int r; 96 | 97 | n = l = RSTRING(str)->len; 98 | if (rb_scan_args( argc, argv, "01", &val) == 1) { 99 | if (!NIL_P( val)) { 100 | int v = NUM2INT( val); 101 | if (v >= 0) { 102 | if (n >= v) n = v; 103 | } else { 104 | n = -n; 105 | if (n <= v) n = v; 106 | } 107 | } 108 | } 109 | 110 | rb_str_modify(str); 111 | if (n > 0) { 112 | r = l - n; 113 | val = rb_str_new5( str, RSTRING(str)->ptr, n); 114 | memmove(RSTRING(str)->ptr, RSTRING(str)->ptr + n, r); 115 | } else { 116 | r = l + n; 117 | val = rb_str_new5( str, RSTRING(str)->ptr + r, -n); 118 | } 119 | RSTRING(str)->len = r; 120 | OBJ_INFECT(val, str); 121 | return val; 122 | } 123 | 124 | 125 | /* 126 | * call-seq: 127 | * str.cut!( length) -> str 128 | * 129 | * Cut string to length. If nothing was removed, 130 | * nil is returned. 131 | * 132 | * a = "hello" 133 | * a.cut! 4 #=> "hell" 134 | * a #=> "hell" 135 | * a.cut! 4 #=> nil 136 | */ 137 | 138 | VALUE 139 | rb_str_cut_bang( VALUE str, VALUE len) 140 | { 141 | int l = NUM2INT( len); 142 | 143 | rb_str_modify(str); 144 | if (l < RSTRING(str)->len) { 145 | RSTRING(str)->len = l; 146 | return str; 147 | } 148 | return Qnil; 149 | } 150 | 151 | 152 | /* 153 | * call-seq: 154 | * str.clear -> self 155 | * 156 | * Set to empty string. Equivalent to str.replace "". 157 | * 158 | * a = "hello" #=> "hello" 159 | * a.clear #=> "" 160 | * a.empty? #=> true 161 | */ 162 | 163 | VALUE 164 | rb_str_clear( VALUE str) 165 | { 166 | rb_str_modify(str); 167 | rb_str_resize(str, 0); 168 | return str; 169 | } 170 | 171 | 172 | /* 173 | * call-seq: 174 | * str.head( n) -> str 175 | * 176 | * Returns first n bytes in str. 177 | * 178 | * "hello".head( 2) #=> "he" 179 | */ 180 | 181 | VALUE 182 | rb_str_head( VALUE str, VALUE n) 183 | { 184 | VALUE str2; 185 | long len; 186 | 187 | len = NUM2LONG(n); 188 | if (len < 0) return Qnil; 189 | if (len > RSTRING(str)->len) { 190 | len = RSTRING(str)->len; 191 | } 192 | str2 = rb_str_new5(str, RSTRING(str)->ptr, len); 193 | OBJ_INFECT(str2, str); 194 | 195 | return str2; 196 | } 197 | 198 | 199 | /* 200 | * call-seq: 201 | * str.rest( n) -> str 202 | * 203 | * Return rest after n bytes in str. 204 | * 205 | * "hello".rest( 2) #=> "llo" 206 | */ 207 | 208 | VALUE 209 | rb_str_rest( VALUE str, VALUE n) 210 | { 211 | VALUE str2; 212 | long beg, len; 213 | 214 | beg = NUM2LONG(n); 215 | if (beg > RSTRING(str)->len) return Qnil; 216 | if (beg < 0) { 217 | beg = 0; 218 | } 219 | len = RSTRING(str)->len - beg; 220 | str2 = rb_str_new5(str, RSTRING(str)->ptr+beg, len); 221 | OBJ_INFECT(str2, str); 222 | 223 | return str2; 224 | } 225 | 226 | 227 | /* 228 | * call-seq: 229 | * str.tail( n) -> str 230 | * 231 | * Returns last n bytes in str. 232 | * 233 | * "hello".tail( 2) #=> "lo" 234 | */ 235 | 236 | VALUE 237 | rb_str_tail( VALUE str, VALUE n) 238 | { 239 | VALUE str2; 240 | long beg, len; 241 | 242 | len = NUM2LONG(n); 243 | if (len < 0) return Qnil; 244 | beg = RSTRING(str)->len - len; 245 | if (beg < 0) { 246 | beg = 0; 247 | len = RSTRING(str)->len; 248 | } 249 | str2 = rb_str_new5(str, RSTRING(str)->ptr+beg, len); 250 | OBJ_INFECT(str2, str); 251 | 252 | return str2; 253 | } 254 | 255 | 256 | /* 257 | * call-seq: 258 | * str.starts_with( oth) -> nil or int 259 | * 260 | * Checks whether the head is oth. Returns length of 261 | * oth when matching. 262 | * 263 | * "sys-apps".starts_with( "sys-") #=> 4 264 | */ 265 | 266 | VALUE 267 | rb_str_starts_with( VALUE str, VALUE oth) 268 | { 269 | long i; 270 | char *s, *o; 271 | 272 | i = RSTRING(oth)->len; 273 | if (i > RSTRING(str)->len) 274 | return Qnil; 275 | s = RSTRING(str)->ptr; 276 | o = RSTRING(oth)->ptr; 277 | for (; i; i--, s++, o++) { 278 | if (*s != *o) 279 | return Qnil; 280 | } 281 | return INT2NUM( RSTRING(oth)->len); 282 | } 283 | 284 | 285 | /* 286 | * call-seq: 287 | * str.ends_with( oth) -> nil or int 288 | * 289 | * Checks whether the tail is oth. Returns the position 290 | * where oth starts when matching. 291 | * 292 | * "sys-apps".ends_with( "-apps") #=> 3 293 | */ 294 | 295 | VALUE 296 | rb_str_ends_with( VALUE str, VALUE oth) 297 | { 298 | long i; 299 | char *s, *o; 300 | 301 | i = RSTRING(oth)->len; 302 | if (i > RSTRING(str)->len) 303 | return Qnil; 304 | s = RSTRING(str)->ptr + RSTRING(str)->len; 305 | o = RSTRING(oth)->ptr + RSTRING(oth)->len; 306 | for (; i; i--) 307 | if (*--s != *--o) 308 | return Qnil; 309 | return INT2NUM( RSTRING(str)->len - RSTRING(oth)->len); 310 | } 311 | 312 | 313 | /* 314 | * call-seq: 315 | * ary.notempty? -> nil or self 316 | * 317 | * Returns self if and only if ary is not 318 | * empty, nil otherwise. 319 | * 320 | * %w(a b).notempty? #=> [ "a", "b"] 321 | * [].notempty? #=> nil 322 | */ 323 | 324 | VALUE 325 | rb_ary_notempty( VALUE ary) 326 | { 327 | return RARRAY( ary)->len == 0 ? Qnil : ary; 328 | } 329 | 330 | 331 | /* 332 | * call-seq: 333 | * array.indexes() -> ary 334 | * array.keys() -> ary 335 | * 336 | * Returns the indexes from 0 to 337 | * array.length() as an array. 338 | * 339 | * [ "a", "h", "q"].indexes #=> [ 0, 1, 2] 340 | */ 341 | 342 | VALUE 343 | rb_ary_indexes( VALUE ary) 344 | { 345 | VALUE ret; 346 | int i, j; 347 | 348 | j = RARRAY( ary)->len; 349 | ret = rb_ary_new2( j); 350 | RARRAY( ret)->len = j; 351 | for (i = 0; j; ++i, --j) { 352 | rb_ary_store( ret, i, INT2NUM(i)); 353 | } 354 | return ret; 355 | } 356 | 357 | 358 | /* 359 | * call-seq: 360 | * array.pick { |elem| ... } -> obj or nil 361 | * 362 | * Deletes the element where the block first returns 363 | * true. Or nil if nothing is found. 364 | * 365 | * a = %w(ant bat cat dog) 366 | * a.pick { |e| e =~ /^c/ } #=> "cat" 367 | * a #=> ["ant", "bat", "dog"] 368 | * a.pick { |e| e =~ /^x/ } #=> nil 369 | */ 370 | 371 | VALUE 372 | rb_ary_pick( VALUE ary) 373 | { 374 | VALUE pos; 375 | 376 | pos = step_index_blk( ary); 377 | if (!NIL_P( pos)) return rb_funcall( ary, id_delete_at, 1, pos); 378 | return Qnil; 379 | } 380 | 381 | VALUE 382 | step_index_blk( VALUE ary) 383 | { 384 | long i; 385 | 386 | for (i = 0; i < RARRAY( ary)->len; i++) { 387 | if (rb_yield( RARRAY( ary)->ptr[ i])) 388 | return LONG2NUM( i); 389 | } 390 | return Qnil; 391 | } 392 | 393 | /* 394 | * call-seq: 395 | * array.rpick { |elem| ... } -> obj or nil 396 | * 397 | * Deletes the element where the block first returns 398 | * true. Or nil if nothing is found. Search 399 | * from right to left. 400 | * 401 | * a = %w(ant cow bat cat dog) 402 | * a.rpick { |e| e =~ /^c/ } #=> "cat" 403 | * a #=> ["ant", "cow", "bat", "dog"] 404 | * a.rpick { |e| e =~ /^x/ } #=> nil 405 | */ 406 | 407 | VALUE 408 | rb_ary_rpick( VALUE ary) 409 | { 410 | VALUE pos; 411 | 412 | pos = step_rindex_blk( ary); 413 | if (!NIL_P( pos)) return rb_funcall( ary, id_delete_at, 1, pos); 414 | return Qnil; 415 | } 416 | 417 | VALUE 418 | step_rindex_blk( VALUE ary) 419 | { 420 | long i; 421 | 422 | for (i = RARRAY( ary)->len; i;) { 423 | --i; 424 | if (rb_yield( RARRAY( ary)->ptr[ i])) 425 | return LONG2NUM( i); 426 | } 427 | return Qnil; 428 | } 429 | 430 | 431 | #ifdef ARRAY_INDEX_WITH_BLOCK 432 | 433 | /* 434 | * call-seq: 435 | * array.index( obj) -> int or nil 436 | * array.index() { |elem| ... } -> int or nil 437 | * 438 | * Returns the index of the first object in self such that 439 | * is == to obj or the block returns 440 | * true. If no match is found, nil is 441 | * returned. 442 | * 443 | * a = %w(a b c d e) 444 | * a.index("b") #=> 1 445 | * a.index("z") #=> nil 446 | * a.index { |e| e >= "b" } #=> 1 447 | * a.index { |e| e >= "q" } #=> nil 448 | */ 449 | 450 | VALUE 451 | rb_ary_index( int argc, VALUE *argv, VALUE ary) 452 | { 453 | VALUE val; 454 | 455 | if (rb_scan_args( argc, argv, "01", &val) == 1) { 456 | if (rb_block_given_p()) rb_warning( "given block not used"); 457 | return step_index_val( ary, val); 458 | } 459 | else { 460 | return step_index_blk( ary); 461 | } 462 | return Qnil; 463 | } 464 | 465 | VALUE 466 | step_index_val( VALUE ary, VALUE val) 467 | { 468 | long i; 469 | 470 | for (i = 0; i < RARRAY( ary)->len; i++) { 471 | if (rb_equal( RARRAY( ary)->ptr[ i], val)) 472 | return LONG2NUM( i); 473 | } 474 | return Qnil; 475 | } 476 | 477 | 478 | /* 479 | * call-seq: 480 | * array.rindex( obj) -> int or nil 481 | * array.rindex() { |elem| ... } -> int or nil 482 | * 483 | * Returns the index of the first object in self such that 484 | * is == to obj or the block returns 485 | * true. If no match is found, nil is 486 | * returned. Search from right to left. 487 | * 488 | * a = %w(a b c d e) 489 | * a.rindex("b") #=> 1 490 | * a.rindex("z") #=> nil 491 | * a.rindex { |e| e >= "b" } #=> 4 492 | * a.rindex { |e| e >= "q" } #=> nil 493 | */ 494 | 495 | VALUE 496 | rb_ary_rindex( int argc, VALUE *argv, VALUE ary) 497 | { 498 | VALUE val; 499 | 500 | if (rb_scan_args( argc, argv, "01", &val) == 1) { 501 | if (rb_block_given_p()) rb_warning( "given block not used"); 502 | return step_rindex_val( ary, val); 503 | } 504 | else { 505 | return step_rindex_blk( ary); 506 | } 507 | return Qnil; 508 | } 509 | 510 | VALUE 511 | step_rindex_val( VALUE ary, VALUE val) 512 | { 513 | long i; 514 | 515 | for (i = RARRAY( ary)->len; i;) { 516 | --i; 517 | if (rb_equal( RARRAY( ary)->ptr[ i], val)) 518 | return LONG2NUM( i); 519 | } 520 | return Qnil; 521 | } 522 | 523 | #endif 524 | 525 | 526 | 527 | /* 528 | * call-seq: 529 | * num.grammatical sing, plu -> str 530 | * 531 | * Singular or plural 532 | * 533 | * 1.grammatical "line", "lines" #=> "line" 534 | * 6.grammatical "child", "children" #=> "children" 535 | */ 536 | 537 | VALUE 538 | rb_num_grammatical( VALUE num, VALUE sing, VALUE plu) 539 | { 540 | long l; 541 | double d; 542 | 543 | switch (TYPE(num)) { 544 | case T_FIXNUM: 545 | l = NUM2LONG(num); 546 | if (l == 1l || l == -1l) 547 | return sing; 548 | break; 549 | 550 | case T_BIGNUM: 551 | /* 1 is not a Bignum */ 552 | break; 553 | 554 | case T_FLOAT: 555 | d = RFLOAT(num)->value; 556 | if (d == 1.0 || d == -1.0) 557 | return sing; 558 | break; 559 | 560 | default: 561 | break; 562 | } 563 | return plu; 564 | } 565 | 566 | 567 | /* 568 | * call-seq: 569 | * hash.notempty? -> nil or self 570 | * 571 | * Returns self if and only if hash is not 572 | * empty, nil otherwise. 573 | * 574 | * { :a => "A"}.notempty? #=> { :a => "A"} 575 | * {}.notempty? #=> nil 576 | */ 577 | 578 | VALUE 579 | rb_hash_notempty( VALUE hash) 580 | { 581 | return RHASH(hash)->tbl->num_entries == 0 ? Qnil : hash; 582 | } 583 | 584 | 585 | 586 | /* 587 | * call-seq: 588 | * file.size -> integer 589 | * 590 | * Returns file's size. A shortcut for 591 | * file.stat.size. This constitutes consistency with 592 | * StringIO. 593 | * 594 | * file.size #=> 16384 595 | */ 596 | 597 | VALUE 598 | rb_file_size( VALUE obj) 599 | { 600 | OpenFile *fptr; 601 | struct stat st; 602 | 603 | GetOpenFile(obj, fptr); 604 | if (fstat(fileno(fptr->f), &st) == -1) { 605 | rb_sys_fail(fptr->path); 606 | } 607 | return INT2FIX(st.st_size); 608 | } 609 | 610 | 611 | /* 612 | * call-seq: 613 | * mtch.begin( n = nil) -> integer 614 | * 615 | * Returns the offset of the start of the nth element of 616 | * the match array in the string. In case n is 617 | * nil the 0th match (whole) is assumed. 618 | * 619 | * m = /(.)(.)(\d+)(\d)/.match("THX1138.") 620 | * m.begin( 0) #=> 1 621 | * m.begin #=> 1 622 | * m.begin( 2) #=> 2 623 | */ 624 | 625 | VALUE 626 | rb_match_begin( int argc, VALUE *argv, VALUE match) 627 | { 628 | VALUE val; 629 | int i; 630 | 631 | if (rb_scan_args( argc, argv, "01", &val) == 1) { 632 | i = NIL_P( val) ? 0 : NUM2INT( val); 633 | } else 634 | i = 0; 635 | 636 | if (i < 0 || RMATCH(match)->regs->num_regs <= i) 637 | rb_raise( rb_eIndexError, "index %d out of matches", i); 638 | 639 | if (RMATCH(match)->regs->beg[i] < 0) 640 | return Qnil; 641 | 642 | return INT2FIX(RMATCH(match)->regs->beg[i]); 643 | } 644 | 645 | 646 | /* 647 | * call-seq: 648 | * mtch.end( n = nil) -> integer 649 | * 650 | * Returns the offset of the character immediately following the end of 651 | * the nth element of the match array in the string. In 652 | * case n is nil the 0th match (whole) is 653 | * assumed. 654 | * 655 | * m = /(.)(.)(\d+)(\d)/.match("THX1138.") 656 | * m.end( 0) #=> 7 657 | * m.end #=> 7 658 | * m.end( 2) #=> 3 659 | */ 660 | 661 | VALUE 662 | rb_match_end( int argc, VALUE *argv, VALUE match) 663 | { 664 | VALUE val; 665 | int i; 666 | 667 | if (rb_scan_args( argc, argv, "01", &val) == 1) { 668 | i = NIL_P( val) ? 0 : NUM2INT( val); 669 | } else 670 | i = 0; 671 | 672 | if (i < 0 || RMATCH(match)->regs->num_regs <= i) 673 | rb_raise( rb_eIndexError, "index %d out of matches", i); 674 | 675 | if (RMATCH(match)->regs->beg[i] < 0) 676 | return Qnil; 677 | 678 | return INT2FIX(RMATCH(match)->regs->end[i]); 679 | } 680 | 681 | 682 | 683 | 684 | /* 685 | * call-seq: 686 | * Struct[ ...] -> cls 687 | * 688 | * Alias for Struct.new; This applies to Struct subclass generation 689 | * as well as to the subclasses instance creation. 690 | * 691 | * S = Struct[ :a, :b] #=> S 692 | * s = S[ 'A', 'B'] #=> # 693 | * 694 | */ 695 | 696 | 697 | void Init_step( void) 698 | { 699 | rb_define_alias( rb_cObject, "cls", "class"); 700 | #ifdef KERNEL_TAP 701 | rb_define_method( rb_mKernel, "tap", rb_krn_tap, 0); 702 | #endif 703 | 704 | rb_define_method( rb_cString, "notempty?", rb_str_notempty, 0); 705 | rb_define_method( rb_cString, "eat", rb_str_eat, -1); 706 | rb_define_method( rb_cString, "cut!", rb_str_cut_bang, 1); 707 | rb_define_method( rb_cString, "clear", rb_str_clear, 0); 708 | rb_define_method( rb_cString, "head", rb_str_head, 1); 709 | rb_define_method( rb_cString, "rest", rb_str_rest, 1); 710 | rb_define_method( rb_cString, "tail", rb_str_tail, 1); 711 | rb_define_method( rb_cString, "starts_with", rb_str_starts_with, 1); 712 | rb_define_method( rb_cString, "ends_with", rb_str_ends_with, 1); 713 | 714 | rb_define_method( rb_cNumeric, "grammatical", rb_num_grammatical, 2); 715 | 716 | rb_define_method( rb_cArray, "notempty?", rb_ary_notempty, 0); 717 | rb_define_method( rb_cArray, "indexes", rb_ary_indexes, 0); 718 | rb_define_alias( rb_cArray, "keys", "indexes"); 719 | rb_define_method( rb_cArray, "pick", rb_ary_pick, 0); 720 | rb_define_method( rb_cArray, "rpick", rb_ary_rpick, 0); 721 | #ifdef ARRAY_INDEX_WITH_BLOCK 722 | rb_define_method( rb_cArray, "index", rb_ary_index, -1); 723 | rb_define_method( rb_cArray, "rindex", rb_ary_rindex, -1); 724 | #endif 725 | 726 | rb_define_method( rb_cHash, "notempty?", rb_hash_notempty, 0); 727 | 728 | rb_define_method( rb_cFile, "size", rb_file_size, 0); 729 | 730 | rb_define_method(rb_cMatch, "begin", rb_match_begin, -1); 731 | rb_define_method(rb_cMatch, "end", rb_match_end, -1); 732 | 733 | rb_define_alias( rb_singleton_class( rb_cStruct), "[]", "new"); 734 | 735 | id_delete_at = rb_intern( "delete_at"); 736 | } 737 | 738 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | Ruby Carats 2 | 3 | Copyright (c) 2009 Thomas Sawyer 4 | 5 | 6 | THE RUBY LICENSE 7 | (http://www.ruby-lang.org/en/LICENSE.txt) 8 | 9 | You may redistribute this software and/or modify it under either the terms of 10 | the GPL (see below), or the conditions below: 11 | 12 | 1. You may make and give away verbatim copies of the source form of the 13 | software without restriction, provided that you duplicate all of the 14 | original copyright notices and associated disclaimers. 15 | 16 | 2. You may modify your copy of the software in any way, provided that 17 | you do at least ONE of the following: 18 | 19 | a) place your modifications in the Public Domain or otherwise 20 | make them Freely Available, such as by posting said 21 | modifications to Usenet or an equivalent medium, or by allowing 22 | the author to include your modifications in the software. 23 | 24 | b) use the modified software only within your corporation or 25 | organization. 26 | 27 | c) rename any non-standard executables so the names do not conflict 28 | with standard executables, which must also be provided. 29 | 30 | d) make other distribution arrangements with the author. 31 | 32 | 3. You may distribute the software in object code or executable 33 | form, provided that you do at least ONE of the following: 34 | 35 | a) distribute the executables and library files of the software, 36 | together with instructions (in the manual page or equivalent) 37 | on where to get the original distribution. 38 | 39 | b) accompany the distribution with the machine-readable source of 40 | the software. 41 | 42 | c) give non-standard executables non-standard names, with 43 | instructions on where to get the original software distribution. 44 | 45 | d) make other distribution arrangements with the author. 46 | 47 | 4. You may modify and include the part of the software into any other 48 | software (possibly commercial). But some files in the distribution 49 | are not written by the author, so that they are not under these terms. 50 | 51 | For the list of those files and their copying conditions, see the 52 | file LEGAL. 53 | 54 | 5. The scripts and library files supplied as input to or produced as 55 | output from the software do not automatically fall under the 56 | copyright of the software, but belong to whomever generated them, 57 | and may be sold commercially, and may be aggregated with this 58 | software. 59 | 60 | 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 61 | IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 62 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 63 | PURPOSE. 64 | 65 | ---------------------------------------------------------------------------- 66 | 67 | 68 | GNU GENERAL PUBLIC LICENSE 69 | Version 2, June 1991 70 | 71 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 72 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 73 | Everyone is permitted to copy and distribute verbatim copies 74 | of this license document, but changing it is not allowed. 75 | 76 | Preamble 77 | 78 | The licenses for most software are designed to take away your 79 | freedom to share and change it. By contrast, the GNU General Public 80 | License is intended to guarantee your freedom to share and change free 81 | software--to make sure the software is free for all its users. This 82 | General Public License applies to most of the Free Software 83 | Foundation's software and to any other program whose authors commit to 84 | using it. (Some other Free Software Foundation software is covered by 85 | the GNU Library General Public License instead.) You can apply it to 86 | your programs, too. 87 | 88 | When we speak of free software, we are referring to freedom, not 89 | price. Our General Public Licenses are designed to make sure that you 90 | have the freedom to distribute copies of free software (and charge for 91 | this service if you wish), that you receive source code or can get it 92 | if you want it, that you can change the software or use pieces of it 93 | in new free programs; and that you know you can do these things. 94 | 95 | To protect your rights, we need to make restrictions that forbid 96 | anyone to deny you these rights or to ask you to surrender the rights. 97 | These restrictions translate to certain responsibilities for you if you 98 | distribute copies of the software, or if you modify it. 99 | 100 | For example, if you distribute copies of such a program, whether 101 | gratis or for a fee, you must give the recipients all the rights that 102 | you have. You must make sure that they, too, receive or can get the 103 | source code. And you must show them these terms so they know their 104 | rights. 105 | 106 | We protect your rights with two steps: (1) copyright the software, and 107 | (2) offer you this license which gives you legal permission to copy, 108 | distribute and/or modify the software. 109 | 110 | Also, for each author's protection and ours, we want to make certain 111 | that everyone understands that there is no warranty for this free 112 | software. If the software is modified by someone else and passed on, we 113 | want its recipients to know that what they have is not the original, so 114 | that any problems introduced by others will not reflect on the original 115 | authors' reputations. 116 | 117 | Finally, any free program is threatened constantly by software 118 | patents. We wish to avoid the danger that redistributors of a free 119 | program will individually obtain patent licenses, in effect making the 120 | program proprietary. To prevent this, we have made it clear that any 121 | patent must be licensed for everyone's free use or not licensed at all. 122 | 123 | The precise terms and conditions for copying, distribution and 124 | modification follow. 125 | 126 | GNU GENERAL PUBLIC LICENSE 127 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 128 | 129 | 0. This License applies to any program or other work which contains 130 | a notice placed by the copyright holder saying it may be distributed 131 | under the terms of this General Public License. The "Program", below, 132 | refers to any such program or work, and a "work based on the Program" 133 | means either the Program or any derivative work under copyright law: 134 | that is to say, a work containing the Program or a portion of it, 135 | either verbatim or with modifications and/or translated into another 136 | language. (Hereinafter, translation is included without limitation in 137 | the term "modification".) Each licensee is addressed as "you". 138 | 139 | Activities other than copying, distribution and modification are not 140 | covered by this License; they are outside its scope. The act of 141 | running the Program is not restricted, and the output from the Program 142 | is covered only if its contents constitute a work based on the 143 | Program (independent of having been made by running the Program). 144 | Whether that is true depends on what the Program does. 145 | 146 | 1. You may copy and distribute verbatim copies of the Program's 147 | source code as you receive it, in any medium, provided that you 148 | conspicuously and appropriately publish on each copy an appropriate 149 | copyright notice and disclaimer of warranty; keep intact all the 150 | notices that refer to this License and to the absence of any warranty; 151 | and give any other recipients of the Program a copy of this License 152 | along with the Program. 153 | 154 | You may charge a fee for the physical act of transferring a copy, and 155 | you may at your option offer warranty protection in exchange for a fee. 156 | 157 | 2. You may modify your copy or copies of the Program or any portion 158 | of it, thus forming a work based on the Program, and copy and 159 | distribute such modifications or work under the terms of Section 1 160 | above, provided that you also meet all of these conditions: 161 | 162 | a) You must cause the modified files to carry prominent notices 163 | stating that you changed the files and the date of any change. 164 | 165 | b) You must cause any work that you distribute or publish, that in 166 | whole or in part contains or is derived from the Program or any 167 | part thereof, to be licensed as a whole at no charge to all third 168 | parties under the terms of this License. 169 | 170 | c) If the modified program normally reads commands interactively 171 | when run, you must cause it, when started running for such 172 | interactive use in the most ordinary way, to print or display an 173 | announcement including an appropriate copyright notice and a 174 | notice that there is no warranty (or else, saying that you provide 175 | a warranty) and that users may redistribute the program under 176 | these conditions, and telling the user how to view a copy of this 177 | License. (Exception: if the Program itself is interactive but 178 | does not normally print such an announcement, your work based on 179 | the Program is not required to print an announcement.) 180 | 181 | These requirements apply to the modified work as a whole. If 182 | identifiable sections of that work are not derived from the Program, 183 | and can be reasonably considered independent and separate works in 184 | themselves, then this License, and its terms, do not apply to those 185 | sections when you distribute them as separate works. But when you 186 | distribute the same sections as part of a whole which is a work based 187 | on the Program, the distribution of the whole must be on the terms of 188 | this License, whose permissions for other licensees extend to the 189 | entire whole, and thus to each and every part regardless of who wrote it. 190 | 191 | Thus, it is not the intent of this section to claim rights or contest 192 | your rights to work written entirely by you; rather, the intent is to 193 | exercise the right to control the distribution of derivative or 194 | collective works based on the Program. 195 | 196 | In addition, mere aggregation of another work not based on the Program 197 | with the Program (or with a work based on the Program) on a volume of 198 | a storage or distribution medium does not bring the other work under 199 | the scope of this License. 200 | 201 | 3. You may copy and distribute the Program (or a work based on it, 202 | under Section 2) in object code or executable form under the terms of 203 | Sections 1 and 2 above provided that you also do one of the following: 204 | 205 | a) Accompany it with the complete corresponding machine-readable 206 | source code, which must be distributed under the terms of Sections 207 | 1 and 2 above on a medium customarily used for software interchange; or, 208 | 209 | b) Accompany it with a written offer, valid for at least three 210 | years, to give any third party, for a charge no more than your 211 | cost of physically performing source distribution, a complete 212 | machine-readable copy of the corresponding source code, to be 213 | distributed under the terms of Sections 1 and 2 above on a medium 214 | customarily used for software interchange; or, 215 | 216 | c) Accompany it with the information you received as to the offer 217 | to distribute corresponding source code. (This alternative is 218 | allowed only for noncommercial distribution and only if you 219 | received the program in object code or executable form with such 220 | an offer, in accord with Subsection b above.) 221 | 222 | The source code for a work means the preferred form of the work for 223 | making modifications to it. For an executable work, complete source 224 | code means all the source code for all modules it contains, plus any 225 | associated interface definition files, plus the scripts used to 226 | control compilation and installation of the executable. However, as a 227 | special exception, the source code distributed need not include 228 | anything that is normally distributed (in either source or binary 229 | form) with the major components (compiler, kernel, and so on) of the 230 | operating system on which the executable runs, unless that component 231 | itself accompanies the executable. 232 | 233 | If distribution of executable or object code is made by offering 234 | access to copy from a designated place, then offering equivalent 235 | access to copy the source code from the same place counts as 236 | distribution of the source code, even though third parties are not 237 | compelled to copy the source along with the object code. 238 | 239 | 4. You may not copy, modify, sublicense, or distribute the Program 240 | except as expressly provided under this License. Any attempt 241 | otherwise to copy, modify, sublicense or distribute the Program is 242 | void, and will automatically terminate your rights under this License. 243 | However, parties who have received copies, or rights, from you under 244 | this License will not have their licenses terminated so long as such 245 | parties remain in full compliance. 246 | 247 | 5. You are not required to accept this License, since you have not 248 | signed it. However, nothing else grants you permission to modify or 249 | distribute the Program or its derivative works. These actions are 250 | prohibited by law if you do not accept this License. Therefore, by 251 | modifying or distributing the Program (or any work based on the 252 | Program), you indicate your acceptance of this License to do so, and 253 | all its terms and conditions for copying, distributing or modifying 254 | the Program or works based on it. 255 | 256 | 6. Each time you redistribute the Program (or any work based on the 257 | Program), the recipient automatically receives a license from the 258 | original licensor to copy, distribute or modify the Program subject to 259 | these terms and conditions. You may not impose any further 260 | restrictions on the recipients' exercise of the rights granted herein. 261 | You are not responsible for enforcing compliance by third parties to 262 | this License. 263 | 264 | 7. If, as a consequence of a court judgment or allegation of patent 265 | infringement or for any other reason (not limited to patent issues), 266 | conditions are imposed on you (whether by court order, agreement or 267 | otherwise) that contradict the conditions of this License, they do not 268 | excuse you from the conditions of this License. If you cannot 269 | distribute so as to satisfy simultaneously your obligations under this 270 | License and any other pertinent obligations, then as a consequence you 271 | may not distribute the Program at all. For example, if a patent 272 | license would not permit royalty-free redistribution of the Program by 273 | all those who receive copies directly or indirectly through you, then 274 | the only way you could satisfy both it and this License would be to 275 | refrain entirely from distribution of the Program. 276 | 277 | If any portion of this section is held invalid or unenforceable under 278 | any particular circumstance, the balance of the section is intended to 279 | apply and the section as a whole is intended to apply in other 280 | circumstances. 281 | 282 | It is not the purpose of this section to induce you to infringe any 283 | patents or other property right claims or to contest validity of any 284 | such claims; this section has the sole purpose of protecting the 285 | integrity of the free software distribution system, which is 286 | implemented by public license practices. Many people have made 287 | generous contributions to the wide range of software distributed 288 | through that system in reliance on consistent application of that 289 | system; it is up to the author/donor to decide if he or she is willing 290 | to distribute software through any other system and a licensee cannot 291 | impose that choice. 292 | 293 | This section is intended to make thoroughly clear what is believed to 294 | be a consequence of the rest of this License. 295 | 296 | 8. If the distribution and/or use of the Program is restricted in 297 | certain countries either by patents or by copyrighted interfaces, the 298 | original copyright holder who places the Program under this License 299 | may add an explicit geographical distribution limitation excluding 300 | those countries, so that distribution is permitted only in or among 301 | countries not thus excluded. In such case, this License incorporates 302 | the limitation as if written in the body of this License. 303 | 304 | 9. The Free Software Foundation may publish revised and/or new versions 305 | of the General Public License from time to time. Such new versions will 306 | be similar in spirit to the present version, but may differ in detail to 307 | address new problems or concerns. 308 | 309 | Each version is given a distinguishing version number. If the Program 310 | specifies a version number of this License which applies to it and "any 311 | later version", you have the option of following the terms and conditions 312 | either of that version or of any later version published by the Free 313 | Software Foundation. If the Program does not specify a version number of 314 | this License, you may choose any version ever published by the Free Software 315 | Foundation. 316 | 317 | 10. If you wish to incorporate parts of the Program into other free 318 | programs whose distribution conditions are different, write to the author 319 | to ask for permission. For software which is copyrighted by the Free 320 | Software Foundation, write to the Free Software Foundation; we sometimes 321 | make exceptions for this. Our decision will be guided by the two goals 322 | of preserving the free status of all derivatives of our free software and 323 | of promoting the sharing and reuse of software generally. 324 | 325 | NO WARRANTY 326 | 327 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 328 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 329 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 330 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 331 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 332 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 333 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 334 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 335 | REPAIR OR CORRECTION. 336 | 337 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 338 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 339 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 340 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 341 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 342 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 343 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 344 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 345 | POSSIBILITY OF SUCH DAMAGES. 346 | 347 | END OF TERMS AND CONDITIONS 348 | 349 | -------------------------------------------------------------------------------- /ext/basicobject/basicobject.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | 3 | basicobject.c - 4 | 5 | $Author$ 6 | created at: Thu Jul 15 12:01:24 JST 1993 7 | 8 | Copyright (C) 1993-2007 Yukihiro Matsumoto 9 | Copyright (C) 2000 Network Applied Communication Laboratory, Inc. 10 | Copyright (C) 2000 Information-technology Promotion Agency, Japan 11 | 12 | **********************************************************************/ 13 | 14 | #include "ruby/ruby.h" 15 | #include "ruby/st.h" 16 | #include "ruby/util.h" 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | VALUE rb_cBasicObject; 24 | //VALUE rb_mKernel; 25 | //VALUE rb_cObject; 26 | //VALUE rb_cModule; 27 | //VALUE rb_cClass; 28 | //VALUE rb_cData; 29 | 30 | //VALUE rb_cNilClass; 31 | //VALUE rb_cTrueClass; 32 | //VALUE rb_cFalseClass; 33 | 34 | static ID id_eq, id_eql, id_match, id_inspect; 35 | static ID id_init_copy, id_init_clone, id_init_dup; 36 | 37 | /* 38 | * call-seq: 39 | * obj === other => true or false 40 | * 41 | * Case Equality---For class Object, effectively the same 42 | * as calling #==, but typically overridden by descendants 43 | * to provide meaningful semantics in case statements. 44 | */ 45 | 46 | VALUE 47 | rb_equal(VALUE obj1, VALUE obj2) 48 | { 49 | VALUE result; 50 | 51 | if (obj1 == obj2) return Qtrue; 52 | result = rb_funcall(obj1, id_eq, 1, obj2); 53 | if (RTEST(result)) return Qtrue; 54 | return Qfalse; 55 | } 56 | 57 | int 58 | rb_eql(VALUE obj1, VALUE obj2) 59 | { 60 | return RTEST(rb_funcall(obj1, id_eql, 1, obj2)); 61 | } 62 | 63 | /* 64 | * call-seq: 65 | * obj == other => true or false 66 | * obj.equal?(other) => true or false 67 | * obj.eql?(other) => true or false 68 | * 69 | * Equality---At the Object level, == returns 70 | * true only if obj and other are the 71 | * same object. Typically, this method is overridden in descendant 72 | * classes to provide class-specific meaning. 73 | * 74 | * Unlike ==, the equal? method should never be 75 | * overridden by subclasses: it is used to determine object identity 76 | * (that is, a.equal?(b) iff a is the same 77 | * object as b). 78 | * 79 | * The eql? method returns true if 80 | * obj and anObject have the same value. Used by 81 | * Hash to test members for equality. For objects of 82 | * class Object, eql? is synonymous with 83 | * ==. Subclasses normally continue this tradition, but 84 | * there are exceptions. Numeric types, for example, 85 | * perform type conversion across ==, but not across 86 | * eql?, so: 87 | * 88 | * 1 == 1.0 #=> true 89 | * 1.eql? 1.0 #=> false 90 | */ 91 | 92 | VALUE 93 | rb_obj_equal(VALUE obj1, VALUE obj2) 94 | { 95 | if (obj1 == obj2) return Qtrue; 96 | return Qfalse; 97 | } 98 | 99 | VALUE 100 | rb_obj_hash(VALUE obj) 101 | { 102 | VALUE oid = rb_obj_id(obj); 103 | st_index_t h = rb_hash_end(rb_hash_start(NUM2LONG(oid))); 104 | return LONG2FIX(h); 105 | } 106 | 107 | /* 108 | * call-seq: 109 | * !obj => true or false 110 | * 111 | * Boolean negate. 112 | */ 113 | 114 | VALUE 115 | rb_obj_not(VALUE obj) 116 | { 117 | return RTEST(obj) ? Qfalse : Qtrue; 118 | } 119 | 120 | /* 121 | * call-seq: 122 | * obj != other => true or false 123 | * 124 | * Returns true if two objects are not-equal, otherwise false. 125 | */ 126 | 127 | VALUE 128 | rb_obj_not_equal(VALUE obj1, VALUE obj2) 129 | { 130 | VALUE result = rb_funcall(obj1, id_eq, 1, obj2); 131 | return RTEST(result) ? Qfalse : Qtrue; 132 | } 133 | 134 | VALUE 135 | rb_class_real(VALUE cl) 136 | { 137 | if (cl == 0) 138 | return 0; 139 | while ((RBASIC(cl)->flags & FL_SINGLETON) || BUILTIN_TYPE(cl) == T_ICLASS) { 140 | cl = RCLASS_SUPER(cl); 141 | } 142 | return cl; 143 | } 144 | 145 | /* 146 | * call-seq: 147 | * obj.class => class 148 | * 149 | * Returns the class of obj, now preferred over 150 | * Object#type, as an object's type in Ruby is only 151 | * loosely tied to that object's class. This method must always be 152 | * called with an explicit receiver, as class is also a 153 | * reserved word in Ruby. 154 | * 155 | * 1.class #=> Fixnum 156 | * self.class #=> Object 157 | */ 158 | 159 | VALUE 160 | rb_obj_class(VALUE obj) 161 | { 162 | return rb_class_real(CLASS_OF(obj)); 163 | } 164 | 165 | /* 166 | * call-seq: 167 | * obj.singleton_class => class 168 | * 169 | * Returns the singleton class of obj. This method creates 170 | * a new singleton class if obj does not have it. 171 | * 172 | * If obj is nil, true, or 173 | * false, it returns NilClass, TrueClass, or FalseClass, 174 | * respectively. 175 | * If obj is a Fixnum or a Symbol, it raises a TypeError. 176 | * 177 | * Object.new.singleton_class #=> #> 178 | * String.singleton_class #=> # 179 | * nil.singleton_class #=> NilClass 180 | */ 181 | 182 | static VALUE 183 | rb_obj_singleton_class(VALUE obj) 184 | { 185 | return rb_singleton_class(obj); 186 | } 187 | 188 | static void 189 | init_copy(VALUE dest, VALUE obj) 190 | { 191 | if (OBJ_FROZEN(dest)) { 192 | rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest)); 193 | } 194 | RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR); 195 | RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR|FL_TAINT|FL_UNTRUSTED); 196 | rb_copy_generic_ivar(dest, obj); 197 | rb_gc_copy_finalizer(dest, obj); 198 | switch (TYPE(obj)) { 199 | case T_OBJECT: 200 | if (!(RBASIC(dest)->flags & ROBJECT_EMBED) && ROBJECT_IVPTR(dest)) { 201 | xfree(ROBJECT_IVPTR(dest)); 202 | ROBJECT(dest)->as.heap.ivptr = 0; 203 | ROBJECT(dest)->as.heap.numiv = 0; 204 | ROBJECT(dest)->as.heap.iv_index_tbl = 0; 205 | } 206 | if (RBASIC(obj)->flags & ROBJECT_EMBED) { 207 | MEMCPY(ROBJECT(dest)->as.ary, ROBJECT(obj)->as.ary, VALUE, ROBJECT_EMBED_LEN_MAX); 208 | RBASIC(dest)->flags |= ROBJECT_EMBED; 209 | } 210 | else { 211 | long len = ROBJECT(obj)->as.heap.numiv; 212 | VALUE *ptr = ALLOC_N(VALUE, len); 213 | MEMCPY(ptr, ROBJECT(obj)->as.heap.ivptr, VALUE, len); 214 | ROBJECT(dest)->as.heap.ivptr = ptr; 215 | ROBJECT(dest)->as.heap.numiv = len; 216 | ROBJECT(dest)->as.heap.iv_index_tbl = ROBJECT(obj)->as.heap.iv_index_tbl; 217 | RBASIC(dest)->flags &= ~ROBJECT_EMBED; 218 | } 219 | break; 220 | case T_CLASS: 221 | case T_MODULE: 222 | if (RCLASS_IV_TBL(dest)) { 223 | st_free_table(RCLASS_IV_TBL(dest)); 224 | RCLASS_IV_TBL(dest) = 0; 225 | } 226 | if (RCLASS_IV_TBL(obj)) { 227 | RCLASS_IV_TBL(dest) = st_copy(RCLASS_IV_TBL(obj)); 228 | } 229 | break; 230 | } 231 | } 232 | 233 | /* 234 | * call-seq: 235 | * obj.clone -> an_object 236 | * 237 | * Produces a shallow copy of obj---the instance variables of 238 | * obj are copied, but not the objects they reference. Copies 239 | * the frozen and tainted state of obj. See also the discussion 240 | * under Object#dup. 241 | * 242 | * class Klass 243 | * attr_accessor :str 244 | * end 245 | * s1 = Klass.new #=> # 246 | * s1.str = "Hello" #=> "Hello" 247 | * s2 = s1.clone #=> # 248 | * s2.str[1,4] = "i" #=> "i" 249 | * s1.inspect #=> "#" 250 | * s2.inspect #=> "#" 251 | * 252 | * This method may have class-specific behavior. If so, that 253 | * behavior will be documented under the #+initialize_copy+ method of 254 | * the class. 255 | */ 256 | 257 | VALUE 258 | rb_obj_clone(VALUE obj) 259 | { 260 | VALUE clone; 261 | 262 | if (rb_special_const_p(obj)) { 263 | rb_raise(rb_eTypeError, "can't clone %s", rb_obj_classname(obj)); 264 | } 265 | clone = rb_obj_alloc(rb_obj_class(obj)); 266 | RBASIC(clone)->klass = rb_singleton_class_clone(obj); 267 | RBASIC(clone)->flags = (RBASIC(obj)->flags | FL_TEST(clone, FL_TAINT) | FL_TEST(clone, FL_UNTRUSTED)) & ~(FL_FREEZE|FL_FINALIZE); 268 | init_copy(clone, obj); 269 | rb_funcall(clone, id_init_clone, 1, obj); 270 | RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE; 271 | 272 | return clone; 273 | } 274 | 275 | /* 276 | * call-seq: 277 | * obj.dup -> an_object 278 | * 279 | * Produces a shallow copy of obj---the instance variables of 280 | * obj are copied, but not the objects they reference. 281 | * dup copies the tainted state of obj. See also 282 | * the discussion under Object#clone. In general, 283 | * clone and dup may have different semantics 284 | * in descendant classes. While clone is used to duplicate 285 | * an object, including its internal state, dup typically 286 | * uses the class of the descendant object to create the new instance. 287 | * 288 | * This method may have class-specific behavior. If so, that 289 | * behavior will be documented under the #+initialize_copy+ method of 290 | * the class. 291 | */ 292 | 293 | VALUE 294 | rb_obj_dup(VALUE obj) 295 | { 296 | VALUE dup; 297 | 298 | if (rb_special_const_p(obj)) { 299 | rb_raise(rb_eTypeError, "can't dup %s", rb_obj_classname(obj)); 300 | } 301 | dup = rb_obj_alloc(rb_obj_class(obj)); 302 | init_copy(dup, obj); 303 | rb_funcall(dup, id_init_dup, 1, obj); 304 | 305 | return dup; 306 | } 307 | 308 | /* :nodoc: */ 309 | VALUE 310 | rb_obj_init_copy(VALUE obj, VALUE orig) 311 | { 312 | if (obj == orig) return obj; 313 | rb_check_frozen(obj); 314 | if (TYPE(obj) != TYPE(orig) || rb_obj_class(obj) != rb_obj_class(orig)) { 315 | rb_raise(rb_eTypeError, "initialize_copy should take same class object"); 316 | } 317 | return obj; 318 | } 319 | 320 | /* :nodoc: */ 321 | VALUE 322 | rb_obj_init_dup_clone(VALUE obj, VALUE orig) 323 | { 324 | rb_funcall(obj, id_init_copy, 1, orig); 325 | return obj; 326 | } 327 | 328 | /* 329 | * call-seq: 330 | * obj.to_s => string 331 | * 332 | * Returns a string representing obj. The default 333 | * to_s prints the object's class and an encoding of the 334 | * object id. As a special case, the top-level object that is the 335 | * initial execution context of Ruby programs returns ``main.'' 336 | */ 337 | 338 | VALUE 339 | rb_any_to_s(VALUE obj) 340 | { 341 | const char *cname = rb_obj_classname(obj); 342 | VALUE str; 343 | 344 | str = rb_sprintf("#<%s:%p>", cname, (void*)obj); 345 | OBJ_INFECT(str, obj); 346 | 347 | return str; 348 | } 349 | 350 | VALUE 351 | rb_inspect(VALUE obj) 352 | { 353 | return rb_obj_as_string(rb_funcall(obj, id_inspect, 0, 0)); 354 | } 355 | 356 | static int 357 | inspect_i(ID id, VALUE value, VALUE str) 358 | { 359 | VALUE str2; 360 | const char *ivname; 361 | 362 | /* need not to show internal data */ 363 | if (CLASS_OF(value) == 0) return ST_CONTINUE; 364 | if (!rb_is_instance_id(id)) return ST_CONTINUE; 365 | if (RSTRING_PTR(str)[0] == '-') { /* first element */ 366 | RSTRING_PTR(str)[0] = '#'; 367 | rb_str_cat2(str, " "); 368 | } 369 | else { 370 | rb_str_cat2(str, ", "); 371 | } 372 | ivname = rb_id2name(id); 373 | rb_str_cat2(str, ivname); 374 | rb_str_cat2(str, "="); 375 | str2 = rb_inspect(value); 376 | rb_str_append(str, str2); 377 | OBJ_INFECT(str, str2); 378 | 379 | return ST_CONTINUE; 380 | } 381 | 382 | static VALUE 383 | inspect_obj(VALUE obj, VALUE str, int recur) 384 | { 385 | if (recur) { 386 | rb_str_cat2(str, " ..."); 387 | } 388 | else { 389 | rb_ivar_foreach(obj, inspect_i, str); 390 | } 391 | rb_str_cat2(str, ">"); 392 | RSTRING_PTR(str)[0] = '#'; 393 | OBJ_INFECT(str, obj); 394 | 395 | return str; 396 | } 397 | 398 | /* 399 | * call-seq: 400 | * obj.inspect => string 401 | * 402 | * Returns a string containing a human-readable representation of 403 | * obj. If not overridden and no instance variables, uses the 404 | * to_s method to generate the string. 405 | * obj. If not overridden, uses the to_s method to 406 | * generate the string. 407 | * 408 | * [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]" 409 | * Time.new.inspect #=> "2008-03-08 19:43:39 +0900" 410 | */ 411 | 412 | static VALUE 413 | rb_obj_inspect(VALUE obj) 414 | { 415 | extern int rb_obj_basic_to_s_p(VALUE); 416 | 417 | if (TYPE(obj) == T_OBJECT && rb_obj_basic_to_s_p(obj)) { 418 | int has_ivar = 0; 419 | VALUE *ptr = ROBJECT_IVPTR(obj); 420 | long len = ROBJECT_NUMIV(obj); 421 | long i; 422 | 423 | for (i = 0; i < len; i++) { 424 | if (ptr[i] != Qundef) { 425 | has_ivar = 1; 426 | break; 427 | } 428 | } 429 | 430 | if (has_ivar) { 431 | VALUE str; 432 | const char *c = rb_obj_classname(obj); 433 | 434 | str = rb_sprintf("-<%s:%p", c, (void*)obj); 435 | return rb_exec_recursive(inspect_obj, obj, str); 436 | } 437 | return rb_any_to_s(obj); 438 | } 439 | return rb_funcall(obj, rb_intern("to_s"), 0, 0); 440 | } 441 | 442 | 443 | /* 444 | * call-seq: 445 | * obj.instance_of?(class) => true or false 446 | * 447 | * Returns true if obj is an instance of the given 448 | * class. See also Object#kind_of?. 449 | */ 450 | 451 | VALUE 452 | rb_obj_is_instance_of(VALUE obj, VALUE c) 453 | { 454 | switch (TYPE(c)) { 455 | case T_MODULE: 456 | case T_CLASS: 457 | case T_ICLASS: 458 | break; 459 | default: 460 | rb_raise(rb_eTypeError, "class or module required"); 461 | } 462 | 463 | if (rb_obj_class(obj) == c) return Qtrue; 464 | return Qfalse; 465 | } 466 | 467 | 468 | /* 469 | * call-seq: 470 | * obj.is_a?(class) => true or false 471 | * obj.kind_of?(class) => true or false 472 | * 473 | * Returns true if class is the class of 474 | * obj, or if class is one of the superclasses of 475 | * obj or modules included in obj. 476 | * 477 | * module M; end 478 | * class A 479 | * include M 480 | * end 481 | * class B < A; end 482 | * class C < B; end 483 | * b = B.new 484 | * b.instance_of? A #=> false 485 | * b.instance_of? B #=> true 486 | * b.instance_of? C #=> false 487 | * b.instance_of? M #=> false 488 | * b.kind_of? A #=> true 489 | * b.kind_of? B #=> true 490 | * b.kind_of? C #=> false 491 | * b.kind_of? M #=> true 492 | */ 493 | 494 | VALUE 495 | rb_obj_is_kind_of(VALUE obj, VALUE c) 496 | { 497 | VALUE cl = CLASS_OF(obj); 498 | 499 | switch (TYPE(c)) { 500 | case T_MODULE: 501 | case T_CLASS: 502 | case T_ICLASS: 503 | break; 504 | 505 | default: 506 | rb_raise(rb_eTypeError, "class or module required"); 507 | } 508 | 509 | while (cl) { 510 | if (cl == c || RCLASS_M_TBL(cl) == RCLASS_M_TBL(c)) 511 | return Qtrue; 512 | cl = RCLASS_SUPER(cl); 513 | } 514 | return Qfalse; 515 | } 516 | 517 | 518 | /* 519 | * call-seq: 520 | * obj.tap{|x|...} => obj 521 | * 522 | * Yields x to the block, and then returns x. 523 | * The primary purpose of this method is to "tap into" a method chain, 524 | * in order to perform operations on intermediate results within the chain. 525 | * 526 | * (1..10) .tap {|x| puts "original: #{x.inspect}"} 527 | * .to_a .tap {|x| puts "array: #{x.inspect}"} 528 | * .select {|x| x%2==0} .tap {|x| puts "evens: #{x.inspect}"} 529 | * .map { |x| x*x } .tap {|x| puts "squares: #{x.inspect}"} 530 | * 531 | */ 532 | 533 | VALUE 534 | rb_obj_tap(VALUE obj) 535 | { 536 | rb_yield(obj); 537 | return obj; 538 | } 539 | 540 | 541 | /* 542 | * Document-method: inherited 543 | * 544 | * call-seq: 545 | * inherited(subclass) 546 | * 547 | * Callback invoked whenever a subclass of the current class is created. 548 | * 549 | * Example: 550 | * 551 | * class Foo 552 | * def self.inherited(subclass) 553 | * puts "New subclass: #{subclass}" 554 | * end 555 | * end 556 | * 557 | * class Bar < Foo 558 | * end 559 | * 560 | * class Baz < Bar 561 | * end 562 | * 563 | * produces: 564 | * 565 | * New subclass: Bar 566 | * New subclass: Baz 567 | */ 568 | 569 | /* 570 | * Document-method: singleton_method_added 571 | * 572 | * call-seq: 573 | * singleton_method_added(symbol) 574 | * 575 | * Invoked as a callback whenever a singleton method is added to the 576 | * receiver. 577 | * 578 | * module Chatty 579 | * def Chatty.singleton_method_added(id) 580 | * puts "Adding #{id.id2name}" 581 | * end 582 | * def self.one() end 583 | * def two() end 584 | * def Chatty.three() end 585 | * end 586 | * 587 | * produces: 588 | * 589 | * Adding singleton_method_added 590 | * Adding one 591 | * Adding three 592 | * 593 | */ 594 | 595 | /* 596 | * Document-method: singleton_method_removed 597 | * 598 | * call-seq: 599 | * singleton_method_removed(symbol) 600 | * 601 | * Invoked as a callback whenever a singleton method is removed from 602 | * the receiver. 603 | * 604 | * module Chatty 605 | * def Chatty.singleton_method_removed(id) 606 | * puts "Removing #{id.id2name}" 607 | * end 608 | * def self.one() end 609 | * def two() end 610 | * def Chatty.three() end 611 | * class <produces: 618 | * 619 | * Removing three 620 | * Removing one 621 | */ 622 | 623 | /* 624 | * Document-method: singleton_method_undefined 625 | * 626 | * call-seq: 627 | * singleton_method_undefined(symbol) 628 | * 629 | * Invoked as a callback whenever a singleton method is undefined in 630 | * the receiver. 631 | * 632 | * module Chatty 633 | * def Chatty.singleton_method_undefined(id) 634 | * puts "Undefining #{id.id2name}" 635 | * end 636 | * def Chatty.one() end 637 | * class << self 638 | * undef_method(:one) 639 | * end 640 | * end 641 | * 642 | * produces: 643 | * 644 | * Undefining one 645 | */ 646 | 647 | 648 | /* 649 | * Document-method: included 650 | * 651 | * call-seq: 652 | * included( othermod ) 653 | * 654 | * Callback invoked whenever the receiver is included in another 655 | * module or class. This should be used in preference to 656 | * Module.append_features if your code wants to perform some 657 | * action when a module is included in another. 658 | * 659 | * module A 660 | * def A.included(mod) 661 | * puts "#{self} included in #{mod}" 662 | * end 663 | * end 664 | * module Enumerable 665 | * include A 666 | * end 667 | */ 668 | 669 | /* 670 | * Document-method: initialize 671 | * 672 | * call-seq: 673 | * BasicObject.new( *args ) 674 | * 675 | * Returns a new BasicObject. Arguments are ignored. 676 | */ 677 | 678 | /* 679 | * Not documented 680 | */ 681 | 682 | static VALUE 683 | rb_obj_dummy(void) 684 | { 685 | return Qnil; 686 | } 687 | 688 | /* 689 | * call-seq: 690 | * obj.tainted? => true or false 691 | * 692 | * Returns true if the object is tainted. 693 | */ 694 | 695 | VALUE 696 | rb_obj_tainted(VALUE obj) 697 | { 698 | if (OBJ_TAINTED(obj)) 699 | return Qtrue; 700 | return Qfalse; 701 | } 702 | 703 | /* 704 | * call-seq: 705 | * obj.taint -> obj 706 | * 707 | * Marks obj as tainted---if the $SAFE level is 708 | * set appropriately, many method calls which might alter the running 709 | * programs environment will refuse to accept tainted strings. 710 | */ 711 | 712 | VALUE 713 | rb_obj_taint(VALUE obj) 714 | { 715 | rb_secure(4); 716 | if (!OBJ_TAINTED(obj)) { 717 | if (OBJ_FROZEN(obj)) { 718 | rb_error_frozen("object"); 719 | } 720 | OBJ_TAINT(obj); 721 | } 722 | return obj; 723 | } 724 | 725 | 726 | /* 727 | * call-seq: 728 | * obj.untaint => obj 729 | * 730 | * Removes the taint from obj. 731 | */ 732 | 733 | VALUE 734 | rb_obj_untaint(VALUE obj) 735 | { 736 | rb_secure(3); 737 | if (OBJ_TAINTED(obj)) { 738 | if (OBJ_FROZEN(obj)) { 739 | rb_error_frozen("object"); 740 | } 741 | FL_UNSET(obj, FL_TAINT); 742 | } 743 | return obj; 744 | } 745 | 746 | /* 747 | * call-seq: 748 | * obj.untrusted? => true or false 749 | * 750 | * Returns true if the object is untrusted. 751 | */ 752 | 753 | VALUE 754 | rb_obj_untrusted(VALUE obj) 755 | { 756 | if (OBJ_UNTRUSTED(obj)) 757 | return Qtrue; 758 | return Qfalse; 759 | } 760 | 761 | /* 762 | * call-seq: 763 | * obj.untrust -> obj 764 | * 765 | * Marks obj as untrusted. 766 | */ 767 | 768 | VALUE 769 | rb_obj_untrust(VALUE obj) 770 | { 771 | rb_secure(4); 772 | if (!OBJ_UNTRUSTED(obj)) { 773 | if (OBJ_FROZEN(obj)) { 774 | rb_error_frozen("object"); 775 | } 776 | OBJ_UNTRUST(obj); 777 | } 778 | return obj; 779 | } 780 | 781 | 782 | /* 783 | * call-seq: 784 | * obj.trust => obj 785 | * 786 | * Removes the untrusted mark from obj. 787 | */ 788 | 789 | VALUE 790 | rb_obj_trust(VALUE obj) 791 | { 792 | rb_secure(3); 793 | if (OBJ_UNTRUSTED(obj)) { 794 | if (OBJ_FROZEN(obj)) { 795 | rb_error_frozen("object"); 796 | } 797 | FL_UNSET(obj, FL_UNTRUSTED); 798 | } 799 | return obj; 800 | } 801 | 802 | void 803 | rb_obj_infect(VALUE obj1, VALUE obj2) 804 | { 805 | OBJ_INFECT(obj1, obj2); 806 | } 807 | 808 | static st_table *immediate_frozen_tbl = 0; 809 | 810 | /* 811 | * call-seq: 812 | * obj.freeze => obj 813 | * 814 | * Prevents further modifications to obj. A 815 | * RuntimeError will be raised if modification is attempted. 816 | * There is no way to unfreeze a frozen object. See also 817 | * Object#frozen?. 818 | * 819 | * This method returns self. 820 | * 821 | * a = [ "a", "b", "c" ] 822 | * a.freeze 823 | * a << "z" 824 | * 825 | * produces: 826 | * 827 | * prog.rb:3:in `<<': can't modify frozen array (RuntimeError) 828 | * from prog.rb:3 829 | */ 830 | 831 | VALUE 832 | rb_obj_freeze(VALUE obj) 833 | { 834 | if (!OBJ_FROZEN(obj)) { 835 | if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(obj)) { 836 | rb_raise(rb_eSecurityError, "Insecure: can't freeze object"); 837 | } 838 | OBJ_FREEZE(obj); 839 | if (SPECIAL_CONST_P(obj)) { 840 | if (!immediate_frozen_tbl) { 841 | immediate_frozen_tbl = st_init_numtable(); 842 | } 843 | st_insert(immediate_frozen_tbl, obj, (st_data_t)Qtrue); 844 | } 845 | } 846 | return obj; 847 | } 848 | 849 | /* 850 | * call-seq: 851 | * obj.frozen? => true or false 852 | * 853 | * Returns the freeze status of obj. 854 | * 855 | * a = [ "a", "b", "c" ] 856 | * a.freeze #=> ["a", "b", "c"] 857 | * a.frozen? #=> true 858 | */ 859 | 860 | VALUE 861 | rb_obj_frozen_p(VALUE obj) 862 | { 863 | if (OBJ_FROZEN(obj)) return Qtrue; 864 | if (SPECIAL_CONST_P(obj)) { 865 | if (!immediate_frozen_tbl) return Qfalse; 866 | if (st_lookup(immediate_frozen_tbl, obj, 0)) return Qtrue; 867 | } 868 | return Qfalse; 869 | } 870 | 871 | 872 | /* 873 | * Document-class: NilClass 874 | * 875 | * The class of the singleton object nil. 876 | */ 877 | 878 | /* 879 | * call-seq: 880 | * nil.to_i => 0 881 | * 882 | * Always returns zero. 883 | * 884 | * nil.to_i #=> 0 885 | */ 886 | 887 | 888 | static VALUE 889 | nil_to_i(VALUE obj) 890 | { 891 | return INT2FIX(0); 892 | } 893 | 894 | /* 895 | * call-seq: 896 | * nil.to_f => 0.0 897 | * 898 | * Always returns zero. 899 | * 900 | * nil.to_f #=> 0.0 901 | */ 902 | 903 | static VALUE 904 | nil_to_f(VALUE obj) 905 | { 906 | return DBL2NUM(0.0); 907 | } 908 | 909 | /* 910 | * call-seq: 911 | * nil.to_s => "" 912 | * 913 | * Always returns the empty string. 914 | */ 915 | 916 | static VALUE 917 | nil_to_s(VALUE obj) 918 | { 919 | return rb_usascii_str_new(0, 0); 920 | } 921 | 922 | /* 923 | * Document-method: to_a 924 | * 925 | * call-seq: 926 | * nil.to_a => [] 927 | * 928 | * Always returns an empty array. 929 | * 930 | * nil.to_a #=> [] 931 | */ 932 | 933 | static VALUE 934 | nil_to_a(VALUE obj) 935 | { 936 | return rb_ary_new2(0); 937 | } 938 | 939 | /* 940 | * call-seq: 941 | * nil.inspect => "nil" 942 | * 943 | * Always returns the string "nil". 944 | */ 945 | 946 | static VALUE 947 | nil_inspect(VALUE obj) 948 | { 949 | return rb_usascii_str_new2("nil"); 950 | } 951 | 952 | /*********************************************************************** 953 | * Document-class: TrueClass 954 | * 955 | * The global value true is the only instance of class 956 | * TrueClass and represents a logically true value in 957 | * boolean expressions. The class provides operators allowing 958 | * true to be used in logical expressions. 959 | */ 960 | 961 | 962 | /* 963 | * call-seq: 964 | * true.to_s => "true" 965 | * 966 | * The string representation of true is "true". 967 | */ 968 | 969 | static VALUE 970 | true_to_s(VALUE obj) 971 | { 972 | return rb_usascii_str_new2("true"); 973 | } 974 | 975 | 976 | /* 977 | * call-seq: 978 | * true & obj => true or false 979 | * 980 | * And---Returns false if obj is 981 | * nil or false, true otherwise. 982 | */ 983 | 984 | static VALUE 985 | true_and(VALUE obj, VALUE obj2) 986 | { 987 | return RTEST(obj2)?Qtrue:Qfalse; 988 | } 989 | 990 | /* 991 | * call-seq: 992 | * true | obj => true 993 | * 994 | * Or---Returns true. As anObject is an argument to 995 | * a method call, it is always evaluated; there is no short-circuit 996 | * evaluation in this case. 997 | * 998 | * true | puts("or") 999 | * true || puts("logical or") 1000 | * 1001 | * produces: 1002 | * 1003 | * or 1004 | */ 1005 | 1006 | static VALUE 1007 | true_or(VALUE obj, VALUE obj2) 1008 | { 1009 | return Qtrue; 1010 | } 1011 | 1012 | 1013 | /* 1014 | * call-seq: 1015 | * true ^ obj => !obj 1016 | * 1017 | * Exclusive Or---Returns true if obj is 1018 | * nil or false, false 1019 | * otherwise. 1020 | */ 1021 | 1022 | static VALUE 1023 | true_xor(VALUE obj, VALUE obj2) 1024 | { 1025 | return RTEST(obj2)?Qfalse:Qtrue; 1026 | } 1027 | 1028 | 1029 | /* 1030 | * Document-class: FalseClass 1031 | * 1032 | * The global value false is the only instance of class 1033 | * FalseClass and represents a logically false value in 1034 | * boolean expressions. The class provides operators allowing 1035 | * false to participate correctly in logical expressions. 1036 | * 1037 | */ 1038 | 1039 | /* 1040 | * call-seq: 1041 | * false.to_s => "false" 1042 | * 1043 | * 'nuf said... 1044 | */ 1045 | 1046 | static VALUE 1047 | false_to_s(VALUE obj) 1048 | { 1049 | return rb_usascii_str_new2("false"); 1050 | } 1051 | 1052 | /* 1053 | * call-seq: 1054 | * false & obj => false 1055 | * nil & obj => false 1056 | * 1057 | * And---Returns false. obj is always 1058 | * evaluated as it is the argument to a method call---there is no 1059 | * short-circuit evaluation in this case. 1060 | */ 1061 | 1062 | static VALUE 1063 | false_and(VALUE obj, VALUE obj2) 1064 | { 1065 | return Qfalse; 1066 | } 1067 | 1068 | 1069 | /* 1070 | * call-seq: 1071 | * false | obj => true or false 1072 | * nil | obj => true or false 1073 | * 1074 | * Or---Returns false if obj is 1075 | * nil or false; true otherwise. 1076 | */ 1077 | 1078 | static VALUE 1079 | false_or(VALUE obj, VALUE obj2) 1080 | { 1081 | return RTEST(obj2)?Qtrue:Qfalse; 1082 | } 1083 | 1084 | 1085 | 1086 | /* 1087 | * call-seq: 1088 | * false ^ obj => true or false 1089 | * nil ^ obj => true or false 1090 | * 1091 | * Exclusive Or---If obj is nil or 1092 | * false, returns false; otherwise, returns 1093 | * true. 1094 | * 1095 | */ 1096 | 1097 | static VALUE 1098 | false_xor(VALUE obj, VALUE obj2) 1099 | { 1100 | return RTEST(obj2)?Qtrue:Qfalse; 1101 | } 1102 | 1103 | /* 1104 | * call_seq: 1105 | * nil.nil? => true 1106 | * 1107 | * Only the object nil responds true to nil?. 1108 | */ 1109 | 1110 | static VALUE 1111 | rb_true(VALUE obj) 1112 | { 1113 | return Qtrue; 1114 | } 1115 | 1116 | /* 1117 | * call_seq: 1118 | * nil.nil? => true 1119 | * .nil? => false 1120 | * 1121 | * Only the object nil responds true to nil?. 1122 | */ 1123 | 1124 | 1125 | static VALUE 1126 | rb_false(VALUE obj) 1127 | { 1128 | return Qfalse; 1129 | } 1130 | 1131 | 1132 | /* 1133 | * call-seq: 1134 | * obj =~ other => nil 1135 | * 1136 | * Pattern Match---Overridden by descendants (notably 1137 | * Regexp and String) to provide meaningful 1138 | * pattern-match semantics. 1139 | */ 1140 | 1141 | static VALUE 1142 | rb_obj_match(VALUE obj1, VALUE obj2) 1143 | { 1144 | return Qnil; 1145 | } 1146 | 1147 | /* 1148 | * call-seq: 1149 | * obj !~ other => true or false 1150 | * 1151 | * Returns true if two objects do not match (using the =~ 1152 | * method), otherwise false. 1153 | */ 1154 | 1155 | static VALUE 1156 | rb_obj_not_match(VALUE obj1, VALUE obj2) 1157 | { 1158 | VALUE result = rb_funcall(obj1, id_match, 1, obj2); 1159 | return RTEST(result) ? Qfalse : Qtrue; 1160 | } 1161 | 1162 | 1163 | /* :nodoc: */ 1164 | static VALUE 1165 | rb_obj_cmp(VALUE obj1, VALUE obj2) 1166 | { 1167 | if (obj1 == obj2 || rb_equal(obj1, obj2)) 1168 | return INT2FIX(0); 1169 | return Qnil; 1170 | } 1171 | 1172 | /*********************************************************************** 1173 | * 1174 | * Document-class: Module 1175 | * 1176 | * A Module is a collection of methods and constants. The 1177 | * methods in a module may be instance methods or module methods. 1178 | * Instance methods appear as methods in a class when the module is 1179 | * included, module methods do not. Conversely, module methods may be 1180 | * called without creating an encapsulating object, while instance 1181 | * methods may not. (See Module#module_function) 1182 | * 1183 | * In the descriptions that follow, the parameter sym refers 1184 | * to a symbol, which is either a quoted string or a 1185 | * Symbol (such as :name). 1186 | * 1187 | * module Mod 1188 | * include Math 1189 | * CONST = 1 1190 | * def meth 1191 | * # ... 1192 | * end 1193 | * end 1194 | * Mod.class #=> Module 1195 | * Mod.constants #=> [:CONST, :PI, :E] 1196 | * Mod.instance_methods #=> [:meth] 1197 | * 1198 | */ 1199 | 1200 | /* 1201 | * call-seq: 1202 | * mod.to_s => string 1203 | * 1204 | * Return a string representing this module or class. For basic 1205 | * classes and modules, this is the name. For singletons, we 1206 | * show information on the thing we're attached to as well. 1207 | */ 1208 | 1209 | static VALUE 1210 | rb_mod_to_s(VALUE klass) 1211 | { 1212 | if (FL_TEST(klass, FL_SINGLETON)) { 1213 | VALUE s = rb_usascii_str_new2("#<"); 1214 | VALUE v = rb_iv_get(klass, "__attached__"); 1215 | 1216 | rb_str_cat2(s, "Class:"); 1217 | switch (TYPE(v)) { 1218 | case T_CLASS: case T_MODULE: 1219 | rb_str_append(s, rb_inspect(v)); 1220 | break; 1221 | default: 1222 | rb_str_append(s, rb_any_to_s(v)); 1223 | break; 1224 | } 1225 | rb_str_cat2(s, ">"); 1226 | 1227 | return s; 1228 | } 1229 | return rb_str_dup(rb_class_name(klass)); 1230 | } 1231 | 1232 | /* 1233 | * call-seq: 1234 | * mod.freeze => mod 1235 | * 1236 | * Prevents further modifications to mod. 1237 | * 1238 | * This method returns self. 1239 | */ 1240 | 1241 | static VALUE 1242 | rb_mod_freeze(VALUE mod) 1243 | { 1244 | rb_class_name(mod); 1245 | return rb_obj_freeze(mod); 1246 | } 1247 | 1248 | /* 1249 | * call-seq: 1250 | * mod === obj => true or false 1251 | * 1252 | * Case Equality---Returns true if anObject is an 1253 | * instance of mod or one of mod's descendants. Of 1254 | * limited use for modules, but can be used in case 1255 | * statements to classify objects by class. 1256 | */ 1257 | 1258 | static VALUE 1259 | rb_mod_eqq(VALUE mod, VALUE arg) 1260 | { 1261 | return rb_obj_is_kind_of(arg, mod); 1262 | } 1263 | 1264 | /* 1265 | * call-seq: 1266 | * mod <= other => true, false, or nil 1267 | * 1268 | * Returns true if mod is a subclass of other or 1269 | * is the same as other. Returns 1270 | * nil if there's no relationship between the two. 1271 | * (Think of the relationship in terms of the class definition: 1272 | * "class A arg */ 1295 | while (arg) { 1296 | if (RCLASS_M_TBL(arg) == RCLASS_M_TBL(start)) 1297 | return Qfalse; 1298 | arg = RCLASS_SUPER(arg); 1299 | } 1300 | return Qnil; 1301 | } 1302 | 1303 | /* 1304 | * call-seq: 1305 | * mod < other => true, false, or nil 1306 | * 1307 | * Returns true if mod is a subclass of other. Returns 1308 | * nil if there's no relationship between the two. 1309 | * (Think of the relationship in terms of the class definition: 1310 | * "class A= other => true, false, or nil 1325 | * 1326 | * Returns true if mod is an ancestor of other, or the 1327 | * two modules are the same. Returns 1328 | * nil if there's no relationship between the two. 1329 | * (Think of the relationship in terms of the class definition: 1330 | * "class AA"). 1331 | * 1332 | */ 1333 | 1334 | static VALUE 1335 | rb_mod_ge(VALUE mod, VALUE arg) 1336 | { 1337 | switch (TYPE(arg)) { 1338 | case T_MODULE: 1339 | case T_CLASS: 1340 | break; 1341 | default: 1342 | rb_raise(rb_eTypeError, "compared with non class/module"); 1343 | } 1344 | 1345 | return rb_class_inherited_p(arg, mod); 1346 | } 1347 | 1348 | /* 1349 | * call-seq: 1350 | * mod > other => true, false, or nil 1351 | * 1352 | * Returns true if mod is an ancestor of other. Returns 1353 | * nil if there's no relationship between the two. 1354 | * (Think of the relationship in terms of the class definition: 1355 | * "class AA"). 1356 | * 1357 | */ 1358 | 1359 | static VALUE 1360 | rb_mod_gt(VALUE mod, VALUE arg) 1361 | { 1362 | if (mod == arg) return Qfalse; 1363 | return rb_mod_ge(mod, arg); 1364 | } 1365 | 1366 | /* 1367 | * call-seq: 1368 | * mod <=> other_mod => -1, 0, +1, or nil 1369 | * 1370 | * Comparison---Returns -1 if mod includes other_mod, 0 if 1371 | * mod is the same as other_mod, and +1 if mod is 1372 | * included by other_mod. Returns nil if mod 1373 | * has no relationship with other_mod or if other_mod is 1374 | * not a module. 1375 | */ 1376 | 1377 | static VALUE 1378 | rb_mod_cmp(VALUE mod, VALUE arg) 1379 | { 1380 | VALUE cmp; 1381 | 1382 | if (mod == arg) return INT2FIX(0); 1383 | switch (TYPE(arg)) { 1384 | case T_MODULE: 1385 | case T_CLASS: 1386 | break; 1387 | default: 1388 | return Qnil; 1389 | } 1390 | 1391 | cmp = rb_class_inherited_p(mod, arg); 1392 | if (NIL_P(cmp)) return Qnil; 1393 | if (cmp) { 1394 | return INT2FIX(-1); 1395 | } 1396 | return INT2FIX(1); 1397 | } 1398 | 1399 | static VALUE 1400 | rb_module_s_alloc(VALUE klass) 1401 | { 1402 | VALUE mod = rb_module_new(); 1403 | 1404 | RBASIC(mod)->klass = klass; 1405 | return mod; 1406 | } 1407 | 1408 | static VALUE 1409 | rb_class_s_alloc(VALUE klass) 1410 | { 1411 | return rb_class_boot(0); 1412 | } 1413 | 1414 | /* 1415 | * call-seq: 1416 | * Module.new => mod 1417 | * Module.new {|mod| block } => mod 1418 | * 1419 | * Creates a new anonymous module. If a block is given, it is passed 1420 | * the module object, and the block is evaluated in the context of this 1421 | * module using module_eval. 1422 | * 1423 | * Fred = Module.new do 1424 | * def meth1 1425 | * "hello" 1426 | * end 1427 | * def meth2 1428 | * "bye" 1429 | * end 1430 | * end 1431 | * a = "my string" 1432 | * a.extend(Fred) #=> "my string" 1433 | * a.meth1 #=> "hello" 1434 | * a.meth2 #=> "bye" 1435 | */ 1436 | 1437 | static VALUE 1438 | rb_mod_initialize(VALUE module) 1439 | { 1440 | extern VALUE rb_mod_module_exec(int argc, VALUE *argv, VALUE mod); 1441 | 1442 | if (rb_block_given_p()) { 1443 | rb_mod_module_exec(1, &module, module); 1444 | } 1445 | return Qnil; 1446 | } 1447 | 1448 | /* 1449 | * call-seq: 1450 | * Class.new(super_class=Object) => a_class 1451 | * 1452 | * Creates a new anonymous (unnamed) class with the given superclass 1453 | * (or Object if no parameter is given). You can give a 1454 | * class a name by assigning the class object to a constant. 1455 | * 1456 | */ 1457 | 1458 | static VALUE 1459 | rb_class_initialize(int argc, VALUE *argv, VALUE klass) 1460 | { 1461 | VALUE super; 1462 | 1463 | if (RCLASS_SUPER(klass) != 0 || klass == rb_cBasicObject) { 1464 | rb_raise(rb_eTypeError, "already initialized class"); 1465 | } 1466 | if (argc == 0) { 1467 | super = rb_cObject; 1468 | } 1469 | else { 1470 | rb_scan_args(argc, argv, "01", &super); 1471 | rb_check_inheritable(super); 1472 | } 1473 | RCLASS_SUPER(klass) = super; 1474 | rb_make_metaclass(klass, RBASIC(super)->klass); 1475 | rb_class_inherited(super, klass); 1476 | rb_mod_initialize(klass); 1477 | 1478 | return klass; 1479 | } 1480 | 1481 | /* 1482 | * call-seq: 1483 | * class.allocate() => obj 1484 | * 1485 | * Allocates space for a new object of class's class and does not 1486 | * call initialize on the new instance. The returned object must be an 1487 | * instance of class. 1488 | * 1489 | * klass = Class.new do 1490 | * def initialize(*args) 1491 | * @initialized = true 1492 | * end 1493 | * 1494 | * def initialized? 1495 | * @initialized || false 1496 | * end 1497 | * end 1498 | * 1499 | * klass.allocate.initialized? #=> false 1500 | * 1501 | */ 1502 | 1503 | VALUE 1504 | rb_obj_alloc(VALUE klass) 1505 | { 1506 | VALUE obj; 1507 | 1508 | if (RCLASS_SUPER(klass) == 0 && klass != rb_cBasicObject) { 1509 | rb_raise(rb_eTypeError, "can't instantiate uninitialized class"); 1510 | } 1511 | if (FL_TEST(klass, FL_SINGLETON)) { 1512 | rb_raise(rb_eTypeError, "can't create instance of singleton class"); 1513 | } 1514 | obj = rb_funcall(klass, ID_ALLOCATOR, 0, 0); 1515 | if (rb_obj_class(obj) != rb_class_real(klass)) { 1516 | rb_raise(rb_eTypeError, "wrong instance allocation"); 1517 | } 1518 | return obj; 1519 | } 1520 | 1521 | static VALUE 1522 | rb_class_allocate_instance(VALUE klass) 1523 | { 1524 | NEWOBJ(obj, struct RObject); 1525 | OBJSETUP(obj, klass, T_OBJECT); 1526 | return (VALUE)obj; 1527 | } 1528 | 1529 | /* 1530 | * call-seq: 1531 | * class.new(args, ...) => obj 1532 | * 1533 | * Calls allocate to create a new object of 1534 | * class's class, then invokes that object's 1535 | * initialize method, passing it args. 1536 | * This is the method that ends up getting called whenever 1537 | * an object is constructed using .new. 1538 | * 1539 | */ 1540 | 1541 | VALUE 1542 | rb_class_new_instance(int argc, VALUE *argv, VALUE klass) 1543 | { 1544 | VALUE obj; 1545 | 1546 | obj = rb_obj_alloc(klass); 1547 | rb_obj_call_init(obj, argc, argv); 1548 | 1549 | return obj; 1550 | } 1551 | 1552 | /* 1553 | * call-seq: 1554 | * class.superclass -> a_super_class or nil 1555 | * 1556 | * Returns the superclass of class, or nil. 1557 | * 1558 | * File.superclass #=> IO 1559 | * IO.superclass #=> Object 1560 | * Object.superclass #=> BasicObject 1561 | * class Foo; end 1562 | * class Bar < Foo; end 1563 | * Bar.superclass #=> Foo 1564 | * 1565 | * returns nil when the given class hasn't a parent class: 1566 | * 1567 | * BasicObject.superclass #=> nil 1568 | * 1569 | */ 1570 | 1571 | static VALUE 1572 | rb_class_superclass(VALUE klass) 1573 | { 1574 | VALUE super = RCLASS_SUPER(klass); 1575 | 1576 | if (!super) { 1577 | if (klass == rb_cBasicObject) return Qnil; 1578 | rb_raise(rb_eTypeError, "uninitialized class"); 1579 | } 1580 | while (TYPE(super) == T_ICLASS) { 1581 | super = RCLASS_SUPER(super); 1582 | } 1583 | if (!super) { 1584 | return Qnil; 1585 | } 1586 | return super; 1587 | } 1588 | 1589 | /* 1590 | * call-seq: 1591 | * attr_reader(symbol, ...) => nil 1592 | * attr(symbol, ...) => nil 1593 | * 1594 | * Creates instance variables and corresponding methods that return the 1595 | * value of each instance variable. Equivalent to calling 1596 | * ``attr:name'' on each name in turn. 1597 | */ 1598 | 1599 | static VALUE 1600 | rb_mod_attr_reader(int argc, VALUE *argv, VALUE klass) 1601 | { 1602 | int i; 1603 | 1604 | for (i=0; i nil 1624 | * 1625 | * Creates an accessor method to allow assignment to the attribute 1626 | * aSymbol.id2name. 1627 | */ 1628 | 1629 | static VALUE 1630 | rb_mod_attr_writer(int argc, VALUE *argv, VALUE klass) 1631 | { 1632 | int i; 1633 | 1634 | for (i=0; i nil 1643 | * 1644 | * Defines a named attribute for this module, where the name is 1645 | * symbol.id2name, creating an instance variable 1646 | * (@name) and a corresponding access method to read it. 1647 | * Also creates a method called name= to set the attribute. 1648 | * 1649 | * module Mod 1650 | * attr_accessor(:one, :two) 1651 | * end 1652 | * Mod.instance_methods.sort #=> [:one, :one=, :two, :two=] 1653 | */ 1654 | 1655 | static VALUE 1656 | rb_mod_attr_accessor(int argc, VALUE *argv, VALUE klass) 1657 | { 1658 | int i; 1659 | 1660 | for (i=0; i obj 1669 | * 1670 | * Returns the value of the named constant in mod. 1671 | * 1672 | * Math.const_get(:PI) #=> 3.14159265358979 1673 | * 1674 | * If the constant is not defined or is defined by the ancestors and 1675 | * +inherit+ is false, +NameError+ will be raised. 1676 | */ 1677 | 1678 | static VALUE 1679 | rb_mod_const_get(int argc, VALUE *argv, VALUE mod) 1680 | { 1681 | VALUE name, recur; 1682 | ID id; 1683 | 1684 | if (argc == 1) { 1685 | name = argv[0]; 1686 | recur = Qtrue; 1687 | } 1688 | else { 1689 | rb_scan_args(argc, argv, "11", &name, &recur); 1690 | } 1691 | id = rb_to_id(name); 1692 | if (!rb_is_const_id(id)) { 1693 | rb_name_error(id, "wrong constant name %s", rb_id2name(id)); 1694 | } 1695 | return RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id); 1696 | } 1697 | 1698 | /* 1699 | * call-seq: 1700 | * mod.const_set(sym, obj) => obj 1701 | * 1702 | * Sets the named constant to the given object, returning that object. 1703 | * Creates a new constant if no constant with the given name previously 1704 | * existed. 1705 | * 1706 | * Math.const_set("HIGH_SCHOOL_PI", 22.0/7.0) #=> 3.14285714285714 1707 | * Math::HIGH_SCHOOL_PI - Math::PI #=> 0.00126448926734968 1708 | */ 1709 | 1710 | static VALUE 1711 | rb_mod_const_set(VALUE mod, VALUE name, VALUE value) 1712 | { 1713 | ID id = rb_to_id(name); 1714 | 1715 | if (!rb_is_const_id(id)) { 1716 | rb_name_error(id, "wrong constant name %s", rb_id2name(id)); 1717 | } 1718 | rb_const_set(mod, id, value); 1719 | return value; 1720 | } 1721 | 1722 | /* 1723 | * call-seq: 1724 | * mod.const_defined?(sym, inherit=true) => true or false 1725 | * 1726 | * Returns true if a constant with the given name is 1727 | * defined by mod, or its ancestors if +inherit+ is not false. 1728 | * 1729 | * Math.const_defined? "PI" #=> true 1730 | * IO.const_defined? "SYNC" #=> true 1731 | * IO.const_defined? "SYNC", false #=> false 1732 | */ 1733 | 1734 | static VALUE 1735 | rb_mod_const_defined(int argc, VALUE *argv, VALUE mod) 1736 | { 1737 | VALUE name, recur; 1738 | ID id; 1739 | 1740 | if (argc == 1) { 1741 | name = argv[0]; 1742 | recur = Qtrue; 1743 | } 1744 | else { 1745 | rb_scan_args(argc, argv, "11", &name, &recur); 1746 | } 1747 | id = rb_to_id(name); 1748 | if (!rb_is_const_id(id)) { 1749 | rb_name_error(id, "wrong constant name %s", rb_id2name(id)); 1750 | } 1751 | return RTEST(recur) ? rb_const_defined(mod, id) : rb_const_defined_at(mod, id); 1752 | } 1753 | 1754 | /* 1755 | * call-seq: 1756 | * obj.methods => array 1757 | * 1758 | * Returns a list of the names of methods publicly accessible in 1759 | * obj. This will include all the methods accessible in 1760 | * obj's ancestors. 1761 | * 1762 | * class Klass 1763 | * def kMethod() 1764 | * end 1765 | * end 1766 | * k = Klass.new 1767 | * k.methods[0..9] #=> [:kMethod, :freeze, :nil?, :is_a?, 1768 | * # :class, :instance_variable_set, 1769 | * # :methods, :extend, :__send__, :instance_eval] 1770 | * k.methods.length #=> 42 1771 | */ 1772 | 1773 | static VALUE 1774 | rb_obj_methods(int argc, VALUE *argv, VALUE obj) 1775 | { 1776 | retry: 1777 | if (argc == 0) { 1778 | VALUE args[1]; 1779 | 1780 | args[0] = Qtrue; 1781 | return rb_class_instance_methods(1, args, CLASS_OF(obj)); 1782 | } 1783 | else { 1784 | VALUE recur; 1785 | 1786 | rb_scan_args(argc, argv, "1", &recur); 1787 | if (RTEST(recur)) { 1788 | argc = 0; 1789 | goto retry; 1790 | } 1791 | return rb_obj_singleton_methods(argc, argv, obj); 1792 | } 1793 | } 1794 | 1795 | /* 1796 | * call-seq: 1797 | * obj.protected_methods(all=true) => array 1798 | * 1799 | * Returns the list of protected methods accessible to obj. If 1800 | * the all parameter is set to false, only those methods 1801 | * in the receiver will be listed. 1802 | */ 1803 | 1804 | static VALUE 1805 | rb_obj_protected_methods(int argc, VALUE *argv, VALUE obj) 1806 | { 1807 | if (argc == 0) { /* hack to stop warning */ 1808 | VALUE args[1]; 1809 | 1810 | args[0] = Qtrue; 1811 | return rb_class_protected_instance_methods(1, args, CLASS_OF(obj)); 1812 | } 1813 | return rb_class_protected_instance_methods(argc, argv, CLASS_OF(obj)); 1814 | } 1815 | 1816 | /* 1817 | * call-seq: 1818 | * obj.private_methods(all=true) => array 1819 | * 1820 | * Returns the list of private methods accessible to obj. If 1821 | * the all parameter is set to false, only those methods 1822 | * in the receiver will be listed. 1823 | */ 1824 | 1825 | static VALUE 1826 | rb_obj_private_methods(int argc, VALUE *argv, VALUE obj) 1827 | { 1828 | if (argc == 0) { /* hack to stop warning */ 1829 | VALUE args[1]; 1830 | 1831 | args[0] = Qtrue; 1832 | return rb_class_private_instance_methods(1, args, CLASS_OF(obj)); 1833 | } 1834 | return rb_class_private_instance_methods(argc, argv, CLASS_OF(obj)); 1835 | } 1836 | 1837 | /* 1838 | * call-seq: 1839 | * obj.public_methods(all=true) => array 1840 | * 1841 | * Returns the list of public methods accessible to obj. If 1842 | * the all parameter is set to false, only those methods 1843 | * in the receiver will be listed. 1844 | */ 1845 | 1846 | static VALUE 1847 | rb_obj_public_methods(int argc, VALUE *argv, VALUE obj) 1848 | { 1849 | if (argc == 0) { /* hack to stop warning */ 1850 | VALUE args[1]; 1851 | 1852 | args[0] = Qtrue; 1853 | return rb_class_public_instance_methods(1, args, CLASS_OF(obj)); 1854 | } 1855 | return rb_class_public_instance_methods(argc, argv, CLASS_OF(obj)); 1856 | } 1857 | 1858 | /* 1859 | * call-seq: 1860 | * obj.instance_variable_get(symbol) => obj 1861 | * 1862 | * Returns the value of the given instance variable, or nil if the 1863 | * instance variable is not set. The @ part of the 1864 | * variable name should be included for regular instance 1865 | * variables. Throws a NameError exception if the 1866 | * supplied symbol is not valid as an instance variable name. 1867 | * 1868 | * class Fred 1869 | * def initialize(p1, p2) 1870 | * @a, @b = p1, p2 1871 | * end 1872 | * end 1873 | * fred = Fred.new('cat', 99) 1874 | * fred.instance_variable_get(:@a) #=> "cat" 1875 | * fred.instance_variable_get("@b") #=> 99 1876 | */ 1877 | 1878 | static VALUE 1879 | rb_obj_ivar_get(VALUE obj, VALUE iv) 1880 | { 1881 | ID id = rb_to_id(iv); 1882 | 1883 | if (!rb_is_instance_id(id)) { 1884 | rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); 1885 | } 1886 | return rb_ivar_get(obj, id); 1887 | } 1888 | 1889 | /* 1890 | * call-seq: 1891 | * obj.instance_variable_set(symbol, obj) => obj 1892 | * 1893 | * Sets the instance variable names by symbol to 1894 | * object, thereby frustrating the efforts of the class's 1895 | * author to attempt to provide proper encapsulation. The variable 1896 | * did not have to exist prior to this call. 1897 | * 1898 | * class Fred 1899 | * def initialize(p1, p2) 1900 | * @a, @b = p1, p2 1901 | * end 1902 | * end 1903 | * fred = Fred.new('cat', 99) 1904 | * fred.instance_variable_set(:@a, 'dog') #=> "dog" 1905 | * fred.instance_variable_set(:@c, 'cat') #=> "cat" 1906 | * fred.inspect #=> "#" 1907 | */ 1908 | 1909 | static VALUE 1910 | rb_obj_ivar_set(VALUE obj, VALUE iv, VALUE val) 1911 | { 1912 | ID id = rb_to_id(iv); 1913 | 1914 | if (!rb_is_instance_id(id)) { 1915 | rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); 1916 | } 1917 | return rb_ivar_set(obj, id, val); 1918 | } 1919 | 1920 | /* 1921 | * call-seq: 1922 | * obj.instance_variable_defined?(symbol) => true or false 1923 | * 1924 | * Returns true if the given instance variable is 1925 | * defined in obj. 1926 | * 1927 | * class Fred 1928 | * def initialize(p1, p2) 1929 | * @a, @b = p1, p2 1930 | * end 1931 | * end 1932 | * fred = Fred.new('cat', 99) 1933 | * fred.instance_variable_defined?(:@a) #=> true 1934 | * fred.instance_variable_defined?("@b") #=> true 1935 | * fred.instance_variable_defined?("@c") #=> false 1936 | */ 1937 | 1938 | static VALUE 1939 | rb_obj_ivar_defined(VALUE obj, VALUE iv) 1940 | { 1941 | ID id = rb_to_id(iv); 1942 | 1943 | if (!rb_is_instance_id(id)) { 1944 | rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); 1945 | } 1946 | return rb_ivar_defined(obj, id); 1947 | } 1948 | 1949 | /* 1950 | * call-seq: 1951 | * mod.class_variable_get(symbol) => obj 1952 | * 1953 | * Returns the value of the given class variable (or throws a 1954 | * NameError exception). The @@ part of the 1955 | * variable name should be included for regular class variables 1956 | * 1957 | * class Fred 1958 | * @@foo = 99 1959 | * end 1960 | * Fred.class_variable_get(:@@foo) #=> 99 1961 | */ 1962 | 1963 | static VALUE 1964 | rb_mod_cvar_get(VALUE obj, VALUE iv) 1965 | { 1966 | ID id = rb_to_id(iv); 1967 | 1968 | if (!rb_is_class_id(id)) { 1969 | rb_name_error(id, "`%s' is not allowed as a class variable name", rb_id2name(id)); 1970 | } 1971 | return rb_cvar_get(obj, id); 1972 | } 1973 | 1974 | /* 1975 | * call-seq: 1976 | * obj.class_variable_set(symbol, obj) => obj 1977 | * 1978 | * Sets the class variable names by symbol to 1979 | * object. 1980 | * 1981 | * class Fred 1982 | * @@foo = 99 1983 | * def foo 1984 | * @@foo 1985 | * end 1986 | * end 1987 | * Fred.class_variable_set(:@@foo, 101) #=> 101 1988 | * Fred.new.foo #=> 101 1989 | */ 1990 | 1991 | static VALUE 1992 | rb_mod_cvar_set(VALUE obj, VALUE iv, VALUE val) 1993 | { 1994 | ID id = rb_to_id(iv); 1995 | 1996 | if (!rb_is_class_id(id)) { 1997 | rb_name_error(id, "`%s' is not allowed as a class variable name", rb_id2name(id)); 1998 | } 1999 | rb_cvar_set(obj, id, val); 2000 | return val; 2001 | } 2002 | 2003 | /* 2004 | * call-seq: 2005 | * obj.class_variable_defined?(symbol) => true or false 2006 | * 2007 | * Returns true if the given class variable is defined 2008 | * in obj. 2009 | * 2010 | * class Fred 2011 | * @@foo = 99 2012 | * end 2013 | * Fred.class_variable_defined?(:@@foo) #=> true 2014 | * Fred.class_variable_defined?(:@@bar) #=> false 2015 | */ 2016 | 2017 | static VALUE 2018 | rb_mod_cvar_defined(VALUE obj, VALUE iv) 2019 | { 2020 | ID id = rb_to_id(iv); 2021 | 2022 | if (!rb_is_class_id(id)) { 2023 | rb_name_error(id, "`%s' is not allowed as a class variable name", rb_id2name(id)); 2024 | } 2025 | return rb_cvar_defined(obj, id); 2026 | } 2027 | 2028 | static struct conv_method_tbl { 2029 | const char *method; 2030 | ID id; 2031 | } conv_method_names[] = { 2032 | {"to_int", 0}, 2033 | {"to_ary", 0}, 2034 | {"to_str", 0}, 2035 | {"to_sym", 0}, 2036 | {"to_hash", 0}, 2037 | {"to_proc", 0}, 2038 | {"to_io", 0}, 2039 | {"to_a", 0}, 2040 | {"to_s", 0}, 2041 | {NULL, 0} 2042 | }; 2043 | 2044 | static VALUE 2045 | convert_type(VALUE val, const char *tname, const char *method, int raise) 2046 | { 2047 | ID m = 0; 2048 | int i; 2049 | VALUE r; 2050 | 2051 | for (i=0; conv_method_names[i].method; i++) { 2052 | if (conv_method_names[i].method[0] == method[0] && 2053 | strcmp(conv_method_names[i].method, method) == 0) { 2054 | m = conv_method_names[i].id; 2055 | break; 2056 | } 2057 | } 2058 | if (!m) m = rb_intern(method); 2059 | r = rb_check_funcall(val, m, 0, 0); 2060 | if (r == Qundef) { 2061 | if (raise) { 2062 | rb_raise(rb_eTypeError, "can't convert %s into %s", 2063 | NIL_P(val) ? "nil" : 2064 | val == Qtrue ? "true" : 2065 | val == Qfalse ? "false" : 2066 | rb_obj_classname(val), 2067 | tname); 2068 | } 2069 | return Qnil; 2070 | } 2071 | return r; 2072 | } 2073 | 2074 | VALUE 2075 | rb_convert_type(VALUE val, int type, const char *tname, const char *method) 2076 | { 2077 | VALUE v; 2078 | 2079 | if (TYPE(val) == type) return val; 2080 | v = convert_type(val, tname, method, TRUE); 2081 | if (TYPE(v) != type) { 2082 | const char *cname = rb_obj_classname(val); 2083 | rb_raise(rb_eTypeError, "can't convert %s to %s (%s#%s gives %s)", 2084 | cname, tname, cname, method, rb_obj_classname(v)); 2085 | } 2086 | return v; 2087 | } 2088 | 2089 | VALUE 2090 | rb_check_convert_type(VALUE val, int type, const char *tname, const char *method) 2091 | { 2092 | VALUE v; 2093 | 2094 | /* always convert T_DATA */ 2095 | if (TYPE(val) == type && type != T_DATA) return val; 2096 | v = convert_type(val, tname, method, FALSE); 2097 | if (NIL_P(v)) return Qnil; 2098 | if (TYPE(v) != type) { 2099 | const char *cname = rb_obj_classname(val); 2100 | rb_raise(rb_eTypeError, "can't convert %s to %s (%s#%s gives %s)", 2101 | cname, tname, cname, method, rb_obj_classname(v)); 2102 | } 2103 | return v; 2104 | } 2105 | 2106 | 2107 | static VALUE 2108 | rb_to_integer(VALUE val, const char *method) 2109 | { 2110 | VALUE v; 2111 | 2112 | if (FIXNUM_P(val)) return val; 2113 | if (TYPE(val) == T_BIGNUM) return val; 2114 | v = convert_type(val, "Integer", method, TRUE); 2115 | if (!rb_obj_is_kind_of(v, rb_cInteger)) { 2116 | const char *cname = rb_obj_classname(val); 2117 | rb_raise(rb_eTypeError, "can't convert %s to Integer (%s#%s gives %s)", 2118 | cname, cname, method, rb_obj_classname(v)); 2119 | } 2120 | return v; 2121 | } 2122 | 2123 | VALUE 2124 | rb_check_to_integer(VALUE val, const char *method) 2125 | { 2126 | VALUE v; 2127 | 2128 | if (FIXNUM_P(val)) return val; 2129 | if (TYPE(val) == T_BIGNUM) return val; 2130 | v = convert_type(val, "Integer", method, FALSE); 2131 | if (!rb_obj_is_kind_of(v, rb_cInteger)) { 2132 | return Qnil; 2133 | } 2134 | return v; 2135 | } 2136 | 2137 | VALUE 2138 | rb_to_int(VALUE val) 2139 | { 2140 | return rb_to_integer(val, "to_int"); 2141 | } 2142 | 2143 | static VALUE 2144 | rb_convert_to_integer(VALUE val, int base) 2145 | { 2146 | VALUE tmp; 2147 | 2148 | switch (TYPE(val)) { 2149 | case T_FLOAT: 2150 | if (base != 0) goto arg_error; 2151 | if (RFLOAT_VALUE(val) <= (double)FIXNUM_MAX 2152 | && RFLOAT_VALUE(val) >= (double)FIXNUM_MIN) { 2153 | break; 2154 | } 2155 | return rb_dbl2big(RFLOAT_VALUE(val)); 2156 | 2157 | case T_FIXNUM: 2158 | case T_BIGNUM: 2159 | if (base != 0) goto arg_error; 2160 | return val; 2161 | 2162 | case T_STRING: 2163 | string_conv: 2164 | return rb_str_to_inum(val, base, TRUE); 2165 | 2166 | case T_NIL: 2167 | if (base != 0) goto arg_error; 2168 | rb_raise(rb_eTypeError, "can't convert nil into Integer"); 2169 | break; 2170 | 2171 | default: 2172 | break; 2173 | } 2174 | if (base != 0) { 2175 | tmp = rb_check_string_type(val); 2176 | if (!NIL_P(tmp)) goto string_conv; 2177 | arg_error: 2178 | rb_raise(rb_eArgError, "base specified for non string value"); 2179 | } 2180 | tmp = convert_type(val, "Integer", "to_int", FALSE); 2181 | if (NIL_P(tmp)) { 2182 | return rb_to_integer(val, "to_i"); 2183 | } 2184 | return tmp; 2185 | 2186 | } 2187 | 2188 | VALUE 2189 | rb_Integer(VALUE val) 2190 | { 2191 | return rb_convert_to_integer(val, 0); 2192 | } 2193 | 2194 | /* 2195 | * call-seq: 2196 | * Integer(arg,base=0) => integer 2197 | * 2198 | * Converts arg to a Fixnum or Bignum. 2199 | * Numeric types are converted directly (with floating point numbers 2200 | * being truncated). base (0, or between 2 and 36) is a base for 2201 | * integer string representation. If arg is a String, 2202 | * when base is omitted or equals to zero, radix indicators 2203 | * (0, 0b, and 0x) are honored. 2204 | * In any case, strings should be strictly conformed to numeric 2205 | * representation. This behavior is different from that of 2206 | * String#to_i. Non string values will be converted using 2207 | * to_int, and to_i. 2208 | * 2209 | * Integer(123.999) #=> 123 2210 | * Integer("0x1a") #=> 26 2211 | * Integer(Time.new) #=> 1204973019 2212 | */ 2213 | 2214 | static VALUE 2215 | rb_f_integer(int argc, VALUE *argv, VALUE obj) 2216 | { 2217 | VALUE arg = Qnil; 2218 | int base = 0; 2219 | 2220 | switch (argc) { 2221 | case 2: 2222 | base = NUM2INT(argv[1]); 2223 | case 1: 2224 | arg = argv[0]; 2225 | break; 2226 | default: 2227 | /* should cause ArgumentError */ 2228 | rb_scan_args(argc, argv, "11", NULL, NULL); 2229 | } 2230 | return rb_convert_to_integer(arg, base); 2231 | } 2232 | 2233 | double 2234 | rb_cstr_to_dbl(const char *p, int badcheck) 2235 | { 2236 | const char *q; 2237 | char *end; 2238 | double d; 2239 | const char *ellipsis = ""; 2240 | int w; 2241 | enum {max_width = 20}; 2242 | #define OutOfRange() ((end - p > max_width) ? \ 2243 | (w = max_width, ellipsis = "...") : \ 2244 | (w = (int)(end - p), ellipsis = "")) 2245 | 2246 | if (!p) return 0.0; 2247 | q = p; 2248 | while (ISSPACE(*p)) p++; 2249 | 2250 | if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 2251 | return 0.0; 2252 | } 2253 | 2254 | d = strtod(p, &end); 2255 | if (errno == ERANGE) { 2256 | OutOfRange(); 2257 | rb_warning("Float %.*s%s out of range", w, p, ellipsis); 2258 | errno = 0; 2259 | } 2260 | if (p == end) { 2261 | if (badcheck) { 2262 | bad: 2263 | rb_invalid_str(q, "Float()"); 2264 | } 2265 | return d; 2266 | } 2267 | if (*end) { 2268 | char buf[DBL_DIG * 4 + 10]; 2269 | char *n = buf; 2270 | char *e = buf + sizeof(buf) - 1; 2271 | char prev = 0; 2272 | 2273 | while (p < end && n < e) prev = *n++ = *p++; 2274 | while (*p) { 2275 | if (*p == '_') { 2276 | /* remove underscores between digits */ 2277 | if (badcheck) { 2278 | if (n == buf || !ISDIGIT(prev)) goto bad; 2279 | ++p; 2280 | if (!ISDIGIT(*p)) goto bad; 2281 | } 2282 | else { 2283 | while (*++p == '_'); 2284 | continue; 2285 | } 2286 | } 2287 | prev = *p++; 2288 | if (n < e) *n++ = prev; 2289 | } 2290 | *n = '\0'; 2291 | p = buf; 2292 | 2293 | if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 2294 | return 0.0; 2295 | } 2296 | 2297 | d = strtod(p, &end); 2298 | if (errno == ERANGE) { 2299 | OutOfRange(); 2300 | rb_warning("Float %.*s%s out of range", w, p, ellipsis); 2301 | errno = 0; 2302 | } 2303 | if (badcheck) { 2304 | if (!end || p == end) goto bad; 2305 | while (*end && ISSPACE(*end)) end++; 2306 | if (*end) goto bad; 2307 | } 2308 | } 2309 | if (errno == ERANGE) { 2310 | errno = 0; 2311 | OutOfRange(); 2312 | rb_raise(rb_eArgError, "Float %.*s%s out of range", w, q, ellipsis); 2313 | } 2314 | return d; 2315 | } 2316 | 2317 | double 2318 | rb_str_to_dbl(VALUE str, int badcheck) 2319 | { 2320 | char *s; 2321 | long len; 2322 | 2323 | StringValue(str); 2324 | s = RSTRING_PTR(str); 2325 | len = RSTRING_LEN(str); 2326 | if (s) { 2327 | if (badcheck && memchr(s, '\0', len)) { 2328 | rb_raise(rb_eArgError, "string for Float contains null byte"); 2329 | } 2330 | if (s[len]) { /* no sentinel somehow */ 2331 | char *p = ALLOCA_N(char, len+1); 2332 | 2333 | MEMCPY(p, s, char, len); 2334 | p[len] = '\0'; 2335 | s = p; 2336 | } 2337 | } 2338 | return rb_cstr_to_dbl(s, badcheck); 2339 | } 2340 | 2341 | VALUE 2342 | rb_Float(VALUE val) 2343 | { 2344 | switch (TYPE(val)) { 2345 | case T_FIXNUM: 2346 | return DBL2NUM((double)FIX2LONG(val)); 2347 | 2348 | case T_FLOAT: 2349 | return val; 2350 | 2351 | case T_BIGNUM: 2352 | return DBL2NUM(rb_big2dbl(val)); 2353 | 2354 | case T_STRING: 2355 | return DBL2NUM(rb_str_to_dbl(val, TRUE)); 2356 | 2357 | case T_NIL: 2358 | rb_raise(rb_eTypeError, "can't convert nil into Float"); 2359 | break; 2360 | 2361 | default: 2362 | return rb_convert_type(val, T_FLOAT, "Float", "to_f"); 2363 | } 2364 | } 2365 | 2366 | /* 2367 | * call-seq: 2368 | * Float(arg) => float 2369 | * 2370 | * Returns arg converted to a float. Numeric types are converted 2371 | * directly, the rest are converted using arg.to_f. As of Ruby 2372 | * 1.8, converting nil generates a TypeError. 2373 | * 2374 | * Float(1) #=> 1.0 2375 | * Float("123.456") #=> 123.456 2376 | */ 2377 | 2378 | static VALUE 2379 | rb_f_float(VALUE obj, VALUE arg) 2380 | { 2381 | return rb_Float(arg); 2382 | } 2383 | 2384 | VALUE 2385 | rb_to_float(VALUE val) 2386 | { 2387 | if (TYPE(val) == T_FLOAT) return val; 2388 | if (!rb_obj_is_kind_of(val, rb_cNumeric)) { 2389 | rb_raise(rb_eTypeError, "can't convert %s into Float", 2390 | NIL_P(val) ? "nil" : 2391 | val == Qtrue ? "true" : 2392 | val == Qfalse ? "false" : 2393 | rb_obj_classname(val)); 2394 | } 2395 | return rb_convert_type(val, T_FLOAT, "Float", "to_f"); 2396 | } 2397 | 2398 | VALUE 2399 | rb_check_to_float(VALUE val) 2400 | { 2401 | if (TYPE(val) == T_FLOAT) return val; 2402 | if (!rb_obj_is_kind_of(val, rb_cNumeric)) { 2403 | return Qnil; 2404 | } 2405 | return rb_check_convert_type(val, T_FLOAT, "Float", "to_f"); 2406 | } 2407 | 2408 | double 2409 | rb_num2dbl(VALUE val) 2410 | { 2411 | switch (TYPE(val)) { 2412 | case T_FLOAT: 2413 | return RFLOAT_VALUE(val); 2414 | 2415 | case T_STRING: 2416 | rb_raise(rb_eTypeError, "no implicit conversion to float from string"); 2417 | break; 2418 | 2419 | case T_NIL: 2420 | rb_raise(rb_eTypeError, "no implicit conversion to float from nil"); 2421 | break; 2422 | 2423 | default: 2424 | break; 2425 | } 2426 | 2427 | return RFLOAT_VALUE(rb_Float(val)); 2428 | } 2429 | 2430 | VALUE 2431 | rb_String(VALUE val) 2432 | { 2433 | return rb_convert_type(val, T_STRING, "String", "to_s"); 2434 | } 2435 | 2436 | 2437 | /* 2438 | * call-seq: 2439 | * String(arg) => string 2440 | * 2441 | * Converts arg to a String by calling its 2442 | * to_s method. 2443 | * 2444 | * String(self) #=> "main" 2445 | * String(self.class) #=> "Object" 2446 | * String(123456) #=> "123456" 2447 | */ 2448 | 2449 | static VALUE 2450 | rb_f_string(VALUE obj, VALUE arg) 2451 | { 2452 | return rb_String(arg); 2453 | } 2454 | 2455 | VALUE 2456 | rb_Array(VALUE val) 2457 | { 2458 | VALUE tmp = rb_check_array_type(val); 2459 | 2460 | if (NIL_P(tmp)) { 2461 | tmp = rb_check_convert_type(val, T_ARRAY, "Array", "to_a"); 2462 | if (NIL_P(tmp)) { 2463 | return rb_ary_new3(1, val); 2464 | } 2465 | } 2466 | return tmp; 2467 | } 2468 | 2469 | /* 2470 | * call-seq: 2471 | * Array(arg) => array 2472 | * 2473 | * Returns arg as an Array. First tries to call 2474 | * arg.to_ary, then arg.to_a. 2475 | * 2476 | * Array(1..5) #=> [1, 2, 3, 4, 5] 2477 | */ 2478 | 2479 | static VALUE 2480 | rb_f_array(VALUE obj, VALUE arg) 2481 | { 2482 | return rb_Array(arg); 2483 | } 2484 | 2485 | /* 2486 | * Document-class: Class 2487 | * 2488 | * Classes in Ruby are first-class objects---each is an instance of 2489 | * class Class. 2490 | * 2491 | * When a new class is created (typically using class Name ... 2492 | * end), an object of type Class is created and 2493 | * assigned to a global constant (Name in this case). When 2494 | * Name.new is called to create a new object, the 2495 | * new method in Class is run by default. 2496 | * This can be demonstrated by overriding new in 2497 | * Class: 2498 | * 2499 | * class Class 2500 | * alias oldNew new 2501 | * def new(*args) 2502 | * print "Creating a new ", self.name, "\n" 2503 | * oldNew(*args) 2504 | * end 2505 | * end 2506 | * 2507 | * 2508 | * class Name 2509 | * end 2510 | * 2511 | * 2512 | * n = Name.new 2513 | * 2514 | * produces: 2515 | * 2516 | * Creating a new Name 2517 | * 2518 | * Classes, modules, and objects are interrelated. In the diagram 2519 | * that follows, the vertical arrows represent inheritance, and the 2520 | * parentheses meta-classes. All metaclasses are instances 2521 | * of the class `Class'. 2522 | * +---------+ +-... 2523 | * | | | 2524 | * BasicObject-----|-->(BasicObject)-------|-... 2525 | * ^ | ^ | 2526 | * | | | | 2527 | * Object---------|----->(Object)---------|-... 2528 | * ^ | ^ | 2529 | * | | | | 2530 | * +-------+ | +--------+ | 2531 | * | | | | | | 2532 | * | Module-|---------|--->(Module)-|-... 2533 | * | ^ | | ^ | 2534 | * | | | | | | 2535 | * | Class-|---------|---->(Class)-|-... 2536 | * | ^ | | ^ | 2537 | * | +---+ | +----+ 2538 | * | | 2539 | * obj--->OtherClass---------->(OtherClass)-----------... 2540 | * 2541 | */ 2542 | 2543 | 2544 | /*! 2545 | * Initializes the world of objects and classes. 2546 | * 2547 | * At first, the function bootstraps the class hierarchy. 2548 | * It initializes the most fundamental classes and their metaclasses. 2549 | * - \c BasicObject 2550 | * - \c Object 2551 | * - \c Module 2552 | * - \c Class 2553 | * After the bootstrap step, the class hierarchy becomes as the following 2554 | * diagram. 2555 | * 2556 | * \image html boottime-classes.png 2557 | * 2558 | * Then, the function defines classes, modules and methods as usual. 2559 | * \ingroup class 2560 | */ 2561 | 2562 | /* 2563 | * 2564 | * BasicObject is the parent class of all classes in Ruby. 2565 | * It's an explicit blank class. Object, the root of Ruby's 2566 | * class hierarchy is a direct subclass of BasicObject. Its 2567 | * methods are therefore available to all objects unless explicitly 2568 | * overridden. 2569 | * 2570 | * Object mixes in the Kernel module, making 2571 | * the built-in kernel functions globally accessible. Although the 2572 | * instance methods of Object are defined by the 2573 | * Kernel module, we have chosen to document them here for 2574 | * clarity. 2575 | * 2576 | * In the descriptions of Object's methods, the parameter symbol refers 2577 | * to a symbol, which is either a quoted string or a 2578 | * Symbol (such as :name). 2579 | */ 2580 | 2581 | void 2582 | Init_Object(void) 2583 | { 2584 | // extern void Init_class_hierarchy(void); 2585 | // int i; 2586 | 2587 | // Init_class_hierarchy(); 2588 | 2589 | #undef rb_intern 2590 | #define rb_intern(str) rb_intern_const(str) 2591 | 2592 | rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, -1); 2593 | rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance); 2594 | rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1); 2595 | rb_define_method(rb_cBasicObject, "equal?", rb_obj_equal, 1); 2596 | rb_define_method(rb_cBasicObject, "!", rb_obj_not, 0); 2597 | rb_define_method(rb_cBasicObject, "!=", rb_obj_not_equal, 1); 2598 | 2599 | rb_define_private_method(rb_cBasicObject, "singleton_method_added", rb_obj_dummy, 1); 2600 | rb_define_private_method(rb_cBasicObject, "singleton_method_removed", rb_obj_dummy, 1); 2601 | rb_define_private_method(rb_cBasicObject, "singleton_method_undefined", rb_obj_dummy, 1); 2602 | 2603 | // rb_mKernel = rb_define_module("Kernel"); 2604 | // rb_include_module(rb_cObject, rb_mKernel); 2605 | // rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1); 2606 | // rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1); 2607 | // rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1); 2608 | // rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1); 2609 | // rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1); 2610 | // rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1); 2611 | // 2612 | // rb_define_method(rb_mKernel, "nil?", rb_false, 0); 2613 | // rb_define_method(rb_mKernel, "===", rb_equal, 1); 2614 | // rb_define_method(rb_mKernel, "=~", rb_obj_match, 1); 2615 | // rb_define_method(rb_mKernel, "!~", rb_obj_not_match, 1); 2616 | // rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1); 2617 | // rb_define_method(rb_mKernel, "hash", rb_obj_hash, 0); 2618 | // rb_define_method(rb_mKernel, "<=>", rb_obj_cmp, 1); 2619 | // 2620 | // rb_define_method(rb_mKernel, "class", rb_obj_class, 0); 2621 | // rb_define_method(rb_mKernel, "singleton_class", rb_obj_singleton_class, 0); 2622 | // rb_define_method(rb_mKernel, "clone", rb_obj_clone, 0); 2623 | // rb_define_method(rb_mKernel, "dup", rb_obj_dup, 0); 2624 | // rb_define_method(rb_mKernel, "initialize_copy", rb_obj_init_copy, 1); 2625 | // rb_define_method(rb_mKernel, "initialize_dup", rb_obj_init_dup_clone, 1); 2626 | // rb_define_method(rb_mKernel, "initialize_clone", rb_obj_init_dup_clone, 1); 2627 | // 2628 | // rb_define_method(rb_mKernel, "taint", rb_obj_taint, 0); 2629 | // rb_define_method(rb_mKernel, "tainted?", rb_obj_tainted, 0); 2630 | // rb_define_method(rb_mKernel, "untaint", rb_obj_untaint, 0); 2631 | // rb_define_method(rb_mKernel, "untrust", rb_obj_untrust, 0); 2632 | // rb_define_method(rb_mKernel, "untrusted?", rb_obj_untrusted, 0); 2633 | // rb_define_method(rb_mKernel, "trust", rb_obj_trust, 0); 2634 | // rb_define_method(rb_mKernel, "freeze", rb_obj_freeze, 0); 2635 | // rb_define_method(rb_mKernel, "frozen?", rb_obj_frozen_p, 0); 2636 | // 2637 | // rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0); 2638 | // rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); 2639 | // rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); 2640 | // rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); /* in class.c */ 2641 | // rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, -1); 2642 | // rb_define_method(rb_mKernel, "private_methods", rb_obj_private_methods, -1); 2643 | // rb_define_method(rb_mKernel, "public_methods", rb_obj_public_methods, -1); 2644 | // rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0); /* in variable.c */ 2645 | // rb_define_method(rb_mKernel, "instance_variable_get", rb_obj_ivar_get, 1); 2646 | // rb_define_method(rb_mKernel, "instance_variable_set", rb_obj_ivar_set, 2); 2647 | // rb_define_method(rb_mKernel, "instance_variable_defined?", rb_obj_ivar_defined, 1); 2648 | // rb_define_private_method(rb_mKernel, "remove_instance_variable", 2649 | // rb_obj_remove_instance_variable, 1); /* in variable.c */ 2650 | // 2651 | // rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1); 2652 | // rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1); 2653 | // rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1); 2654 | // rb_define_method(rb_mKernel, "tap", rb_obj_tap, 0); 2655 | // 2656 | // rb_define_global_function("sprintf", rb_f_sprintf, -1); /* in sprintf.c */ 2657 | // rb_define_global_function("format", rb_f_sprintf, -1); /* in sprintf.c */ 2658 | // 2659 | // rb_define_global_function("Integer", rb_f_integer, -1); 2660 | // rb_define_global_function("Float", rb_f_float, 1); 2661 | // 2662 | // rb_define_global_function("String", rb_f_string, 1); 2663 | // rb_define_global_function("Array", rb_f_array, 1); 2664 | // 2665 | // rb_cNilClass = rb_define_class("NilClass", rb_cObject); 2666 | // rb_define_method(rb_cNilClass, "to_i", nil_to_i, 0); 2667 | // rb_define_method(rb_cNilClass, "to_f", nil_to_f, 0); 2668 | // rb_define_method(rb_cNilClass, "to_s", nil_to_s, 0); 2669 | // rb_define_method(rb_cNilClass, "to_a", nil_to_a, 0); 2670 | // rb_define_method(rb_cNilClass, "inspect", nil_inspect, 0); 2671 | // rb_define_method(rb_cNilClass, "&", false_and, 1); 2672 | // rb_define_method(rb_cNilClass, "|", false_or, 1); 2673 | // rb_define_method(rb_cNilClass, "^", false_xor, 1); 2674 | // 2675 | // rb_define_method(rb_cNilClass, "nil?", rb_true, 0); 2676 | // rb_undef_alloc_func(rb_cNilClass); 2677 | // rb_undef_method(CLASS_OF(rb_cNilClass), "new"); 2678 | // rb_define_global_const("NIL", Qnil); 2679 | // 2680 | // rb_define_method(rb_cModule, "freeze", rb_mod_freeze, 0); 2681 | // rb_define_method(rb_cModule, "===", rb_mod_eqq, 1); 2682 | // rb_define_method(rb_cModule, "==", rb_obj_equal, 1); 2683 | // rb_define_method(rb_cModule, "<=>", rb_mod_cmp, 1); 2684 | // rb_define_method(rb_cModule, "<", rb_mod_lt, 1); 2685 | // rb_define_method(rb_cModule, "<=", rb_class_inherited_p, 1); 2686 | // rb_define_method(rb_cModule, ">", rb_mod_gt, 1); 2687 | // rb_define_method(rb_cModule, ">=", rb_mod_ge, 1); 2688 | // rb_define_method(rb_cModule, "initialize_copy", rb_mod_init_copy, 1); /* in class.c */ 2689 | // rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0); 2690 | // rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */ 2691 | // rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */ 2692 | // rb_define_method(rb_cModule, "name", rb_mod_name, 0); /* in variable.c */ 2693 | // rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); /* in class.c */ 2694 | // 2695 | // rb_define_private_method(rb_cModule, "attr", rb_mod_attr, -1); 2696 | // rb_define_private_method(rb_cModule, "attr_reader", rb_mod_attr_reader, -1); 2697 | // rb_define_private_method(rb_cModule, "attr_writer", rb_mod_attr_writer, -1); 2698 | // rb_define_private_method(rb_cModule, "attr_accessor", rb_mod_attr_accessor, -1); 2699 | // 2700 | // rb_define_alloc_func(rb_cModule, rb_module_s_alloc); 2701 | // rb_define_method(rb_cModule, "initialize", rb_mod_initialize, 0); 2702 | // rb_define_method(rb_cModule, "instance_methods", rb_class_instance_methods, -1); /* in class.c */ 2703 | // rb_define_method(rb_cModule, "public_instance_methods", 2704 | // rb_class_public_instance_methods, -1); /* in class.c */ 2705 | // rb_define_method(rb_cModule, "protected_instance_methods", 2706 | // rb_class_protected_instance_methods, -1); /* in class.c */ 2707 | // rb_define_method(rb_cModule, "private_instance_methods", 2708 | // rb_class_private_instance_methods, -1); /* in class.c */ 2709 | // 2710 | // rb_define_method(rb_cModule, "constants", rb_mod_constants, -1); /* in variable.c */ 2711 | // rb_define_method(rb_cModule, "const_get", rb_mod_const_get, -1); 2712 | // rb_define_method(rb_cModule, "const_set", rb_mod_const_set, 2); 2713 | // rb_define_method(rb_cModule, "const_defined?", rb_mod_const_defined, -1); 2714 | // rb_define_private_method(rb_cModule, "remove_const", 2715 | // rb_mod_remove_const, 1); /* in variable.c */ 2716 | // rb_define_method(rb_cModule, "const_missing", 2717 | // rb_mod_const_missing, 1); /* in variable.c */ 2718 | // rb_define_method(rb_cModule, "class_variables", 2719 | // rb_mod_class_variables, 0); /* in variable.c */ 2720 | // rb_define_method(rb_cModule, "remove_class_variable", 2721 | // rb_mod_remove_cvar, 1); /* in variable.c */ 2722 | // rb_define_method(rb_cModule, "class_variable_get", rb_mod_cvar_get, 1); 2723 | // rb_define_method(rb_cModule, "class_variable_set", rb_mod_cvar_set, 2); 2724 | // rb_define_method(rb_cModule, "class_variable_defined?", rb_mod_cvar_defined, 1); 2725 | // 2726 | // rb_define_method(rb_cClass, "allocate", rb_obj_alloc, 0); 2727 | // rb_define_method(rb_cClass, "new", rb_class_new_instance, -1); 2728 | // rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1); 2729 | // rb_define_method(rb_cClass, "initialize_copy", rb_class_init_copy, 1); /* in class.c */ 2730 | // rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0); 2731 | // rb_define_alloc_func(rb_cClass, rb_class_s_alloc); 2732 | // rb_undef_method(rb_cClass, "extend_object"); 2733 | // rb_undef_method(rb_cClass, "append_features"); 2734 | // 2735 | // rb_cData = rb_define_class("Data", rb_cObject); 2736 | // rb_undef_alloc_func(rb_cData); 2737 | // 2738 | // rb_cTrueClass = rb_define_class("TrueClass", rb_cObject); 2739 | // rb_define_method(rb_cTrueClass, "to_s", true_to_s, 0); 2740 | // rb_define_method(rb_cTrueClass, "&", true_and, 1); 2741 | // rb_define_method(rb_cTrueClass, "|", true_or, 1); 2742 | // rb_define_method(rb_cTrueClass, "^", true_xor, 1); 2743 | // rb_undef_alloc_func(rb_cTrueClass); 2744 | // rb_undef_method(CLASS_OF(rb_cTrueClass), "new"); 2745 | // rb_define_global_const("TRUE", Qtrue); 2746 | // 2747 | // rb_cFalseClass = rb_define_class("FalseClass", rb_cObject); 2748 | // rb_define_method(rb_cFalseClass, "to_s", false_to_s, 0); 2749 | // rb_define_method(rb_cFalseClass, "&", false_and, 1); 2750 | // rb_define_method(rb_cFalseClass, "|", false_or, 1); 2751 | // rb_define_method(rb_cFalseClass, "^", false_xor, 1); 2752 | // rb_undef_alloc_func(rb_cFalseClass); 2753 | // rb_undef_method(CLASS_OF(rb_cFalseClass), "new"); 2754 | // rb_define_global_const("FALSE", Qfalse); 2755 | // 2756 | // id_eq = rb_intern("=="); 2757 | // id_eql = rb_intern("eql?"); 2758 | // id_match = rb_intern("=~"); 2759 | // id_inspect = rb_intern("inspect"); 2760 | // id_init_copy = rb_intern("initialize_copy"); 2761 | // id_init_clone = rb_intern("initialize_clone"); 2762 | // id_init_dup = rb_intern("initialize_dup"); 2763 | // 2764 | // for (i=0; conv_method_names[i].method; i++) { 2765 | // conv_method_names[i].id = rb_intern(conv_method_names[i].method); 2766 | // } 2767 | 2768 | } 2769 | 2770 | --------------------------------------------------------------------------------