From 66ffacf58ffb22ace951b853ad69ef6c685b1dde Mon Sep 17 00:00:00 2001 From: dmacvicar Date: Fri, 23 Nov 2007 13:01:16 +0000 Subject: [PATCH] Allows for a different mporting Instead of require 'yast' m = YaST::Module.new("Foo") m.hello We do require 'ycp' require 'ycp/foo' YCP::Foo::hello Much nicer and the symbols are declared so you can even ask the module for its methods Minor other improvements. Calling is broken for now git-svn-id: http://svn.opensuse.org/svn/yast/trunk/ruby-bindings@42363 e0cc52ee-31ee-0310-8b87-e83c4596d67c --- examples/ruby/module-storage-2.rb | 10 + examples/ruby/ruby_from_ycp.ycp | 2 +- examples/ruby/ycp-1.rb | 9 + src/CMakeLists.txt | 2 +- src/ruby/YCP.cc | 132 ++++++-- src/ruby/YCP.rb | 520 ------------------------------ src/ruby/YaPI.pm.in | 246 -------------- src/ruby/yast.rb | 38 +++ src/swig/CMakeLists.txt | 28 +- src/swig/yast.i | 240 +++----------- src/swig/ycp.i | 93 ++++++ src/swig/ycp.rb | 24 ++ 12 files changed, 352 insertions(+), 992 deletions(-) create mode 100644 examples/ruby/module-storage-2.rb create mode 100644 examples/ruby/ycp-1.rb delete mode 100644 src/ruby/YCP.rb delete mode 100644 src/ruby/YaPI.pm.in create mode 100644 src/swig/ycp.i create mode 100644 src/swig/ycp.rb diff --git a/examples/ruby/module-storage-2.rb b/examples/ruby/module-storage-2.rb new file mode 100644 index 0000000..ea89a9f --- /dev/null +++ b/examples/ruby/module-storage-2.rb @@ -0,0 +1,10 @@ +require 'yast' +require 'ycp/storage' + + +puts YCP::Storage.methods + +dp = YCP::Storage::GetDiskPartition("/dev/sda1") +dp.each do | key, value | + puts "#{key} #{value}" +end \ No newline at end of file diff --git a/examples/ruby/ruby_from_ycp.ycp b/examples/ruby/ruby_from_ycp.ycp index b61bd3c..fb1cf52 100644 --- a/examples/ruby/ruby_from_ycp.ycp +++ b/examples/ruby/ruby_from_ycp.ycp @@ -1,6 +1,6 @@ { - import "Duncan"; + import "Foo"; string result = (string) multiply_by_eight(10); UI::OpenDialog( `VBox( diff --git a/examples/ruby/ycp-1.rb b/examples/ruby/ycp-1.rb new file mode 100644 index 0000000..9ff723f --- /dev/null +++ b/examples/ruby/ycp-1.rb @@ -0,0 +1,9 @@ +require 'ycp' +include Ycpx + +f = File.new('/usr/share/YaST2/modules/Arch.ycp') +p = Parser.new( f.fileno, 'Arch') +puts p.class +y = p.parse +puts y.methods +y.is_block diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a3b5fa..279b801 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,2 +1,2 @@ -#ADD_SUBDIRECTORY(swig) +ADD_SUBDIRECTORY(swig) ADD_SUBDIRECTORY(ruby) \ No newline at end of file diff --git a/src/ruby/YCP.cc b/src/ruby/YCP.cc index a2188df..3ffb58b 100644 --- a/src/ruby/YCP.cc +++ b/src/ruby/YCP.cc @@ -56,8 +56,13 @@ as published by the Free Software Foundation; either version #include "Y2RubyTypeConv.h" #include "YRuby.h" +#define GetY2Object(obj, po) \ + Data_Get_Struct(obj, Y2Namespace, po) + static VALUE rb_mYaST; +static VALUE rb_mY2ModuleProxy; static VALUE rb_mUi; +static VALUE rb_mYCP; static VALUE rb_cBroker; // make the compiler happy when @@ -77,13 +82,13 @@ Y2Component *owned_wfmc = 0; static Y2Namespace * -getNs (const char * ns_name, const char * func_name) +getNs (const char * ns_name) { Import import(ns_name); // has a static cache Y2Namespace *ns = import.nameSpace(); if (ns == NULL) { - y2error ("... for a Ruby call of %s", func_name); + y2error ("Ruby call: Can't import namespace '%s'", ns_name); } else { @@ -207,11 +212,90 @@ yast_module_methods( VALUE self ) //forward declaration YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv ); +/** + * looks a component for a namespace + * throws + */ +static VALUE +ycp_module_lookup_namespace_component(VALUE self, VALUE name) +{ + Y2Component *c; + c = Y2ComponentBroker::getNamespaceComponent(RSTRING(name)->ptr); + if (c == NULL) + { + y2internal("No component can provide namespace %s\n", RSTRING (name)->ptr); + rb_raise( rb_eRuntimeError, "No YaST component can provide namespace %s\n", RSTRING (name)->ptr); + } + y2internal("component name %s\n", c->name().c_str()); + return Qtrue; +} + +/* + tries to import a namespace and throws a NameError if + failed +*/ +static VALUE +ycp_module_import_namespace( VALUE self, VALUE namespace_name) +{ + Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr); + if (ns == NULL) + { + rb_raise( rb_eNameError, "Component cannot import namespace '%s'", RSTRING (namespace_name)->ptr); + return Qnil; + } + else + { + y2internal("Namespace created from %s\n", ns->filename().c_str()); + } + return Qtrue; +} + +static VALUE +ycp_module_import( VALUE self, VALUE name) +{ + ycp_module_lookup_namespace_component(self,name); + ycp_module_import_namespace(self,name); +} + +/** + * iterates all symbols in a namespace and yields the + * symbol name and category + */ +VALUE +ycp_module_each_symbol(VALUE self, VALUE namespace_name) +{ + Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr); + if (ns == NULL) + { + rb_raise( rb_eRuntimeError, "Error getting namespace '%s'", RSTRING (namespace_name)->ptr ); + return Qnil; + } + else + { + y2internal("Got namespace from %s\n", ns->filename().c_str()); + } + + for (int i=0; i < ns->symbolCount(); ++i) + { + SymbolEntryPtr s = ns->symbolEntry(i); + VALUE arr = rb_ary_new(); + rb_ary_push(arr, rb_str_new2(s->name())); + rb_ary_push(arr, ID2SYM(rb_intern(s->catString().c_str()))); + rb_yield(arr); + } + return Qnil; +} + +/** + * Forwards a ruby call to the namespace + * First argument is the namespace + * then function name and arguments + */ VALUE -yast_module_proxy_method( int argc, VALUE *argv, VALUE self ) +ycp_module_forward_call(int argc, VALUE *argv, VALUE self) { - VALUE symbol = argv[0]; - VALUE namespace_name = rb_iv_get(self, "@namespace_name"); + VALUE symbol = argv[1]; + VALUE namespace_name = argv[0]; // the func name (1st argument, is a symbol // lets convert it to string @@ -238,30 +322,21 @@ yast_module_proxy_method( int argc, VALUE *argv, VALUE self ) //return Qnil; } - Y2Component *c; - c = Y2ComponentBroker::getNamespaceComponent(RSTRING (namespace_name)->ptr); - if (c == NULL) - { - y2internal("No component can provide namespace %s\n", RSTRING (namespace_name)->ptr); - rb_raise( rb_eRuntimeError, "No component can provide namespace %s\n", RSTRING (namespace_name)->ptr); - return 2; - } - y2internal("component name %s\n", c->name().c_str()); + ycp_module_lookup_namespace_component(self, namespace_name); // import the namespace //Y2Namespace *ns = c->import(RSTRING (namespace_name)->ptr); - Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr); + Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr); if (ns == NULL) { - rb_raise( rb_eRuntimeError, "Component cannot import namespace %s", RSTRING (namespace_name)->ptr ); + rb_raise( rb_eRuntimeError, "Component cannot import namespace '%s' for symbol '%s'", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr ); return Qnil; } else { y2internal("Namespace created from %s\n", ns->filename().c_str()); } - // ensure it is an initialized namespace - //ns->initialize (); + y2internal("Namespace %s initialized\n", RSTRING (namespace_name)->ptr); TableEntry *sym_te = ns->table()->find (RSTRING(symbol_str)->ptr); @@ -276,6 +351,7 @@ yast_module_proxy_method( int argc, VALUE *argv, VALUE self ) if (sym_te->sentry ()->isVariable () || sym_te->sentry ()->isReference ()) { + y2internal ("Variable or reference %s\n", RSTRING(symbol_str)->ptr); // set the variable //ret_yv = YCP_getset_variable (aTHX_ ns_name, sym_te->sentry (), args); } @@ -286,15 +362,16 @@ yast_module_proxy_method( int argc, VALUE *argv, VALUE self ) if (call == NULL) { y2internal ("Cannot create function call %s\n", RSTRING(symbol_str)->ptr); - return 4; + rb_raise( rb_eRuntimeError, "Can't create call to %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr); } // add the parameters - for (int i=1; itoString()); + y2internal ("Appending parameter #%s : %s\n", i, v->toString()); call->appendParameter (v); } call->finishParameters (); @@ -455,16 +532,25 @@ extern "C" } rb_mYaST = rb_define_module("YaST"); - rb_mUi = rb_define_module_under(rb_mYaST, "Ui"); + + //rb_mYCP = rb_define_module_under(rb_mYaST, "YCP"); + rb_mYCP = rb_define_module("YCP"); + rb_define_singleton_method( rb_mYCP, "import", RB_METHOD(ycp_module_import), 1); + rb_define_singleton_method( rb_mYCP, "forward_call", RB_METHOD(ycp_module_forward_call), -1); + rb_define_singleton_method( rb_mYCP, "each_symbol", RB_METHOD(ycp_module_each_symbol), 1); + + + rb_mUi = rb_define_module_under(rb_mYCP, "Ui"); rb_define_singleton_method( rb_mUi, "init", RB_METHOD(rb_init_ui), -1); + rb_define_method( rb_mYaST, "y2_logger", RB_METHOD(rb_y2_logger), -1); rb_cBroker = rb_define_class_under( rb_mYaST, "Module", rb_cObject); //rb_define_singleton_method( rb_cBroker, "new", RB_METHOD(module_new), 1); rb_define_alloc_func(rb_cBroker, yast_module_allocate); rb_define_method(rb_cBroker, "initialize", RB_METHOD(yast_module_initialize), 1); - rb_define_method( rb_cBroker, "method_missing", RB_METHOD(yast_module_proxy_method), -1); + //rb_define_method( rb_cBroker, "method_missing", RB_METHOD(yast_module_proxy_method), -1); rb_define_method( rb_cBroker, "name", RB_METHOD(yast_module_name), -1); ryast_path_init(rb_mYaST); diff --git a/src/ruby/YCP.rb b/src/ruby/YCP.rb deleted file mode 100644 index fb820b5..0000000 --- a/src/ruby/YCP.rb +++ /dev/null @@ -1,520 +0,0 @@ -#! /usr/bin/perl -w -# Martin Vidner -# $Id: YCP.pm 33405 2006-10-13 13:12:42Z mvidner $ - -=head1 NAME - -YaST::YCP - a binary interface between Perl and YCP - -=head1 SYNOPSIS - - use YaST::YCP qw(:DATA :LOGGING); - - YaST::YCP::Import ("SCR"); - my $m = SCR->Read (".sysconfig.displaymanager.DISPLAYMANAGER"); - SCR->Write (".sysconfig.kernel.CRASH_OFTEN", Boolean (1)); - -=head1 DATA TYPES - -YaST has a richer and stricter data type system than Perl. - -Note that the stdio-communicating agents, based on the modules -L and L, have a similar but -not the same data type mapping. - -When the language binding knows what type to expect, eg. when passing -an argument to a YCP function, it will convert a Perl scalar to the -desired type. - -On the other hand, if the type is not known, expressed -in YCP as C, scalars will be passed as strings. If you want -a specific data type, use one of the data classes like -L. Of course these work also when -the type is known. - -=over 4 - -=item void - -Has only one value, C, which is represented as C. -Any data type can have C as a value. - -=item any - -A union of all data types. Any data type can be assigned to it. - -=item string, integer, float, boolean - -B Becomes a scalar - -B Any scalar will become a string -(even if it looks like a number). -Use L, L, L or L -if you want a specific data type. - -=item list ETE - -B A list becomes a reference to an array. -(Note that it refers to a B.) - -B A reference to an array becomes a list. -I -Perl functions returning multiple values should not return a list -but a reference to it. YCP will always set a scalar calling context, -even if the result is assigned to a list. - -=item map ET1, T2E - -B A map becomes a reference to a hash. -(Note that it refers to a B.) - -B A reference to a hash becomes a map. - -=item path - -B NOT IMPLEMENTED YET. - -B If a path is expected, a scalar like C<".foo.bar"> -will be converted to C<.foo.bar>. -Otherwise use L (which is NOT IMPLEMENTED YET). - -=item symbol - -B Becomes a L. - -B If a symbol is expected, a scalar like C<"foo"> -will be converted to C<`foo>. -Otherwise use L. - -=item term - -B Becomes a L. - -B Use L. - -=item byteblock - -B Becomes a scalar. - -B If a byteblock is expected, a scalar like C<"\0\1"> -will be converted to C<#[0001]>. -Otherwise use L. - -=item locale, block ETE, ... - -Not implemented. - -=back - -=head1 YaST::YCP - -The DATA tag (in C) imports the data -constructor functions such as Boolean, Symbol or Term. - -=cut - -package YaST::YCP; -use strict; -use warnings; -use diagnostics; - -require Exporter; -our @ISA = qw(Exporter); -my @e_data = qw(Boolean Byteblock Integer Float String Symbol Term); -my @e_logging = qw(y2debug y2milestone y2warning y2error y2security y2internal); -our @EXPORT_OK = (@e_data, @e_logging, "sformat"); -our %EXPORT_TAGS = ( DATA => [@e_data], LOGGING => [@e_logging] ); - -=head2 debug - - $olddebug = YaST::YCP::debug (1); - YaST::YCP::... - YaST::YCP::debug ($olddebug); - -Enables miscellaneous unscpecified debugging - -=cut - -my $debug = 0; -sub debug (;$) -{ - my $param = shift; - if (defined $param) - { - $debug = $param; - } - return $debug; -} - - -## calls boot_YaST__YCP -require XSLoader; -XSLoader::load ('YaST::YCP'); - -=head2 init_ui - - YaST::YCP::init_ui (); - YaST::YCP::init_ui "qt"; - -Initializes the user interface, "ncurses" (the default) or "qt". - -=cut - -# ensure that the ncurses window is closed -# and wfm and its agents are closed (#39519) -END { - close_components (); # XS -} - -=head2 Import - - YaST::YCP::Import "Namespace"; - Namespace->foo ("bar"); - -Imports a YaST namespace (in YCP or Perl or any supported language). -Equivalent to YCP C, similar to Perl C. - -If C is in YCP, its constructor is executed later than if -it were imported from YCP. This can have subtle effects, for example -in testsuites. To get closer to the YCP import behavior, call -C from a C block. - -=cut - -sub Import ($) -{ - my $package = shift; - print "Importing $package\n" if debug; - - no strict; - # let it get our autoload - *{"${package}::AUTOLOAD"} = \&YaST::YCP::Autoload::AUTOLOAD; -} - -=head2 logging - -These functions go via liby2util and thus use log.conf. -See also ycp::y2milestone. - -The multiple arguments are simply joined by a space. - - y2debug ($message, $message2, ...) - y2milestone ($message, $message2, ...) - y2warning ($message, $message2, ...) - y2error ($message, $message2, ...) - y2security ($message, $message2, ...) - y2internal ($message, $message2, ...) - -=cut - -sub y2_logger_helper ($@) -{ - my $level = shift; - # look _two_ frames up for the subroutine - # when called from the main script, it will be undef - my ($package, $filename, $line, $subroutine) = caller (2); - # look _one_ frame up for file and line - # (is it because of optimization?) - ($package, $filename, $line) = caller (1); - # this is a XS: - y2_logger ($level, "Perl", $filename, $line, $subroutine || "", - join (" ", @_)); -} - -sub y2debug (@) { y2_logger_helper (0, @_); } -sub y2milestone (@) { y2_logger_helper (1, @_); } -sub y2warning (@) { y2_logger_helper (2, @_); } -sub y2error (@) { y2_logger_helper (3, @_); } -sub y2security (@) { y2_logger_helper (4, @_); } -sub y2internal (@) { y2_logger_helper (5, @_); } - -=head2 sformat - -Implements the sformat YCP builtin: - -C returns C<'b % a'> - -It is useful mainly for messages marked for translation. - -=cut - -sub sformat ($@) -{ - # don't shift - # now the % indices can be used for @_ - my $format = $_[0]; - - # g: global, replace all occurences - # e: expression, not a string - $format =~ s{%([1-9%])}{ - ($1 eq '%') ? '%' : $_[$1] - }ge; - - return $format; -} - -# shortcuts for the data types -# for POD see packages below - -sub Boolean ($) -{ - return new YaST::YCP::Boolean (@_); -} - -sub Byteblock ($) -{ - return new YaST::YCP::Byteblock (@_); -} - -sub Integer ($) -{ - return new YaST::YCP::Integer (@_); -} - -sub Float ($) -{ - return new YaST::YCP::Float (@_); -} - -sub String ($) -{ - return new YaST::YCP::String (@_); -} - -sub Symbol ($) -{ - return new YaST::YCP::Symbol (@_); -} - -sub Term ($@) -{ - return new YaST::YCP::Term (@_); -} - -# by defining AUTOLOAD in a separate package, undefined functions in -# the main one will be detected -package YaST::YCP::Autoload; -use strict; -use warnings; -use diagnostics; - -# cannot rely on UNIVERSAL::AUTOLOAD getting automatically called -# http://www.rocketaware.com/perl/perldelta/Deprecated_Inherited_C_AUTOLOAD.htm - -# Gets called instead of all functions in Import'ed modules -# It assumes a normal function, not a class or instance method -sub AUTOLOAD -{ - our $AUTOLOAD; - - # strip $self on the way from Perl to YCP, - # just as it is added in the reverse direction - my $himself = shift; - print "$himself $AUTOLOAD (", join (", ", @_), ")\n" if YaST::YCP::debug; - - my @components = split ("::", $AUTOLOAD); - my $func = pop (@components); - return YaST::YCP::call_ycp (join ("::", @components), $func, @_); -} - -=head2 Boolean - - $b = YaST::YCP::Boolean (1); - $b->value (0); - print $b->value, "\n"; - SCR::Write (".foo", $b); - -=cut - -package YaST::YCP::Boolean; -use strict; -use warnings; -use diagnostics; - -# a Boolean is just a blessed reference to a scalar - -sub new -{ - my $class = shift; - my $val = shift; - return bless \$val, $class -} - -# get/set -sub value -{ - # see "Constructors and Instance Methods" in perltoot - my $self = shift; - if (@_) { $$self = shift; } - return $$self; -} - -=head2 Byteblock - -A chunk of binary data. - - use YaST::YCP qw(:DATA); - - read ($dev_random_fh, $r, 100); - $b = Byteblock ($r); - $b->value ("Hello\0world\0"); - print $b->value, "\n"; - return $b; - -=cut - -package YaST::YCP::Byteblock; -use strict; -use warnings; -use diagnostics; - -# a Byteblock is just a blessed reference to a scalar -# just like Boolean, so use it! - -our @ISA = qw (YaST::YCP::Boolean); - -=head2 Integer - -An explicitly typed integer, useful to put in heterogenous data structures. - - use YaST::YCP qw(:DATA); - - $i = Integer ("42 and more"); - $i->value ("43, actually"); - print $i->value, "\n"; - return [ $i ]; - -=cut - -package YaST::YCP::Integer; -use strict; -use warnings; -use diagnostics; - - -# an Integer is just a blessed reference to a scalar -# just like Boolean, so use it! - -our @ISA = qw (YaST::YCP::Boolean); - -=head2 Float - -An explicitly typed float, useful to put in heterogenous data structures. - - use YaST::YCP qw(:DATA); - - $f = Float ("3.41 is PI"); - $f->value ("3.14 is PI"); - print $f->value, "\n"; - return [ $f ]; - -=cut - -package YaST::YCP::Float; -use strict; -use warnings; -use diagnostics; - - -# a Float is just a blessed reference to a scalar -# just like Boolean, so use it! - -our @ISA = qw (YaST::YCP::Boolean); - -=head2 Path - -Not implemented yet. - -=cut - -=head2 String - -An explicitly typed string, useful to put in heterogenous data structures. - - use YaST::YCP qw(:DATA); - - $s = String (42); - $s->value (1 + 1); - print $s->value, "\n"; - return [ $s ]; - -=cut - -package YaST::YCP::String; -use strict; -use warnings; -use diagnostics; - -# a String is just a blessed reference to a scalar -# just like Boolean, so use it! - -our @ISA = qw (YaST::YCP::Boolean); - -=head2 Symbol - - use YaST::YCP qw(:DATA); - - $s = Symbol ("next"); - $s->value ("back"); - print $s->value, "\n"; - return Term ("id", $s); - -=cut - -package YaST::YCP::Symbol; -use strict; -use warnings; -use diagnostics; - - -# a Symbol is just a blessed reference to a scalar -# just like Boolean, so use it! - -our @ISA = qw (YaST::YCP::Boolean); - -=head2 Term - - $t = new YaST::YCP::Term("CzechBox", "Accept spam", new YaST::YCP::Boolean(0)); - $t->name ("CheckBox"); - print $t->args->[0], "\n"; - UIx::OpenDialog ($t); - -=cut - -package YaST::YCP::Term; -use strict; -use warnings; -use diagnostics; - -# a Term has a name and arguments - -sub new -{ - my $class = shift; - my $name = shift; - my $args = [ @_ ]; - return bless { name => $name, args => $args }, $class -} - -# get/set -sub name -{ - # see "Constructors and Instance Methods" in perltoot - my $self = shift; - if (@_) { $self->{name} = shift; } - return $self->{name}; -} - -# get/set -sub args -{ - # see "Constructors and Instance Methods" in perltoot - my $self = shift; - if (@_) { @{ $self->{args} } = @_; } - # HACK: - # because I don't want to process multiple return values, - # I return it as a reference - return $self->{args}; -} - -1; diff --git a/src/ruby/YaPI.pm.in b/src/ruby/YaPI.pm.in deleted file mode 100644 index c991d30..0000000 --- a/src/ruby/YaPI.pm.in +++ /dev/null @@ -1,246 +0,0 @@ -# -*- perl -*- -# @configure_input@ -# $Id: YaPI.pm.in 33405 2006-10-13 13:12:42Z mvidner $ - -package YaPI; - -=head1 NAME - -YaPI - common functions for modules implementing YaST API - -=cut - -BEGIN { - # substituted by configure - my $modules = '@yast2dir4perl@/modules'; - # unconditional 'use lib' could override a "use lib ." that - # we do during compilation, #197099 - grep { $_ eq $modules } @INC or unshift(@INC, $modules); -} -use strict; - -use Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw(textdomain __); - -use YaST::YCP; -use ycp; - -use Locale::gettext ("!textdomain"); -use POSIX (); # Needed for setlocale() - -POSIX::setlocale(&POSIX::LC_MESSAGES, ""); - -our %TYPEINFO; -my %__error = (); -my $VERSION = ""; -our @CAPABILITIES = (); - -=head2 base functions - -These are to be used by modules that use YaPI as their base class. - - use YaPI; - our @ISA = ("YaPI"); - -=head3 Interface - -Returns a reference to a list of hashes describing the functions -in the current package. The information is taken from TYPEINFO. - - [ - { - functionName => "contains", - return => "boolean", - argument => [ "string", ["list", "string"]], - }, - ... - ] - -=cut - -BEGIN { $TYPEINFO{Interface} = ["function", "any"]; } -sub Interface { - my $self = shift; - my @ret = (); - - no strict "refs"; - my %TI = %{"${self}::TYPEINFO"}; - - foreach my $k (keys %TYPEINFO) { - $TI{$k} = $TYPEINFO{$k}; - } - - foreach my $funcName (sort keys %TI) { - my @dummy = @{$TI{$funcName}}; - my $hash = {}; - - $hash->{'functionName'} = $funcName; - $hash->{'return'} = $dummy[1]; - splice(@dummy, 0, 2); - $hash->{'argument'} = \@dummy; - push @ret, $hash; - } - return \@ret; -} - -=head3 Version - -Returns the version of the current package. - -=cut - -BEGIN { $TYPEINFO{Version} = ["function", "string"]; } -sub Version { - my $self = shift; - no strict "refs"; - return ${"${self}::VERSION"}; -} - -=head3 Supports - -Greps C<@CAPABILITIES> of the current package. - - if (YaPI::Foo->Supports ("frobnicate")) {...} - -=cut - -BEGIN { $TYPEINFO{Supports} = ["function", "boolean", "string"]; } -sub Supports { - my $self = shift; - my $cap = shift; - - no strict "refs"; - my @c = @{"${self}::CAPABILITIES"}; - foreach my $k (@CAPABILITIES) { - push @c, $k; - } - - return !!grep( ($_ eq $cap), @c); -} - - -=head3 SetError - -Logs an error and remembers it for L. - -Error map: - - { - code # mandatory, an uppercase short string - summary - description - # if all of the following are missing, caller () is used - package - file - line - } - -=cut - -BEGIN { $TYPEINFO{SetError} = ["function", "boolean", ["map", "string", "any" ]]; } -sub SetError { - my $self = shift; - %__error = @_; - if( !$__error{package} && !$__error{file} && !$__error{line}) - { - @__error{'package','file','line'} = caller(); - } - if ( defined $__error{summary} ) { - y2error($__error{code}."[".$__error{line}.":".$__error{file}."] ".$__error{summary}); - } else { - y2error($__error{code}); - } - if(defined $__error{description} && $__error{description} ne "") { - y2error("Description: ".$__error{description}); - } - - return undef; -} - -=head3 Error - -Returns the error set by L - -=cut - -BEGIN { $TYPEINFO{Error} = ["function", ["map", "string", "any"] ]; } -sub Error { - my $self = shift; - return \%__error; -} - -=head2 i18n - -C<< use YaPI; >> - -C<< textdomain "mydomain"; >> - -Just use a double underscore to mark text to be translated: C<__("my text")>. -Both C and C<__> are exported to the calling package. - -These must not be used any longer because they collide with symbols -exported by this module: - - # use Locale::gettext; # textdomain - # sub _ { ... } - -These don't hurt but aren't necessary: - - # use POSIX (); - # POSIX::setlocale(LC_MESSAGES, ""); # YaPI calls it itself now - -=head3 textdomain - -Calls Locale::gettext::textdomain -and also -remembers an association between the calling package and the -domain. Later calls of __ use this domain as an argument to dgettext. - -=cut - -# See also bug 38613 where untranslated texts were seen because -# a random textdomain was used instead of the proper one. -my %textdomains; - -sub textdomain -{ - my $domain = shift; - my ($package, $filename, $line) = caller; - - if (defined ($textdomains{package})) - { - if ($textdomains{package} ne $domain) - { - y2error ("Textdomain '$domain' overrides old textdomain '$textdomains{package}' in package $package, $filename:$line"); - } - } - $textdomains{$package} = $domain; - return Locale::gettext::textdomain ($domain); -} - -=head3 __ (double underscore) - -Calls Locale::gettext::dgettext, supplying the textdomain of the calling -package (set by calling textdomain). - -Note: the single underscore function (_) will be removed because it -is automaticaly exported to main:: which causes namespace conflicts. - -=cut - -# bug 39954: __ better than _ -sub __ { - my $msgid = shift; - my $package = caller; - my $domain = $textdomains{$package}; - return Locale::gettext::dgettext ($domain, $msgid); -} - -# Compatibility by partial typeglob assignment: -# &_ will call &__ but $_ will not be $__ which would happen -# if we just asigned *_ = *__. -# Cannot just call __ from _ because of "caller". -*_ = \&__; - -1; diff --git a/src/ruby/yast.rb b/src/ruby/yast.rb index e205cc0..9bc01e9 100644 --- a/src/ruby/yast.rb +++ b/src/ruby/yast.rb @@ -23,6 +23,44 @@ ENV['LD_LIBRARY_PATH'] = "/usr/lib/YaST2/plugin" # Load the native part (.so) require 'yastx' +module YCP + def self.method_missing(id, *args) + puts "stop" + end + + def self.add_ycp_module(mname) + puts "import #{mname}" + YCP::import(mname) + m = Module.new + YCP::each_symbol(mname) do |sname,stype| + if (stype == :function) and !sname.empty? + m.module_eval <<-"END" + def self.#{sname}(*args) + args.insert(0, "#{mname}") + args.insert(0, :#{sname}) + puts "to forward call #{sname.to_s} in #{mname}" + return YCP::forward_call(args) + end + END + end + end + YCP.const_set(mname, m) + end +end + +module Kernel + alias require_ require + def require(name) + if name =~ /^ycp\/(.+)$/ + ycpns = $1 + YCP::add_ycp_module(ycpns.capitalize) + return true + end + return require_(name) + end +end + + module YaST module Ui #my @e_logging = qw(y2debug y2milestone y2warning y2error y2security y2internal); diff --git a/src/swig/CMakeLists.txt b/src/swig/CMakeLists.txt index 2ecda54..8e858a5 100644 --- a/src/swig/CMakeLists.txt +++ b/src/swig/CMakeLists.txt @@ -1,30 +1,32 @@ -SET( SWIG_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/yast_wrap.cxx" ) -SET( SWIG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/yast.i" ) +SET( SWIG_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ycp_wrap.cxx" ) +SET( SWIG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/ycp.i" ) ADD_CUSTOM_COMMAND ( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/yast_wrap.cxx + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ycp_wrap.cxx COMMAND ${CMAKE_COMMAND} -E echo_append "Creating wrapper code..." #COMMAND ${SWIG_EXECUTABLE} -c++ -ruby -autorename -xmlout parse.xml -I/usr/include swig/zypp.i - COMMAND ${SWIG_EXECUTABLE} -I${YAST_INCLUDE_DIR} -c++ -ruby -autorename -xmlout ${CMAKE_CURRENT_BINARY_DIR}/parse.xml -o ${CMAKE_CURRENT_BINARY_DIR}/yast_wrap.cxx -I${ZYPP_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/yast.i + COMMAND ${SWIG_EXECUTABLE} -I${YAST_INCLUDE_DIR} -c++ -ruby -autorename -xmlout ${CMAKE_CURRENT_BINARY_DIR}/parse.xml -o ${CMAKE_CURRENT_BINARY_DIR}/ycp_wrap.cxx -I${ZYPP_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/ycp.i COMMAND ${CMAKE_COMMAND} -E echo "Done." WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/yast.i + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ycp.i ) ADD_CUSTOM_TARGET( glue DEPENDS ${SWIG_OUTPUT} ) -ADD_LIBRARY( ryast SHARED "${CMAKE_CURRENT_BINARY_DIR}/yast_wrap.cxx" ) -SET_TARGET_PROPERTIES( ryast PROPERTIES PREFIX "" ) -ADD_DEPENDENCIES( ryast glue ) +ADD_LIBRARY( ycpx SHARED "${CMAKE_CURRENT_BINARY_DIR}/ycp_wrap.cxx" ) +SET_TARGET_PROPERTIES( ycpx PROPERTIES PREFIX "" ) +ADD_DEPENDENCIES( ycpx glue ) INCLUDE_DIRECTORIES( ${RUBY_INCLUDE_PATH} ) INCLUDE_DIRECTORIES( ${YAST_INCLUDE_DIR} ) -TARGET_LINK_LIBRARIES( ryast ${YAST_LIBRARY} ) -TARGET_LINK_LIBRARIES( ryast ${YAST_YCP_LIBRARY} ) -TARGET_LINK_LIBRARIES( ryast ${YAST_PLUGIN_WFM_LIBRARY} ) -TARGET_LINK_LIBRARIES( ryast ${RUBY_LIBRARY} ) +TARGET_LINK_LIBRARIES( ycpx ${YAST_LIBRARY} ) +TARGET_LINK_LIBRARIES( ycpx ${YAST_YCP_LIBRARY} ) +TARGET_LINK_LIBRARIES( ycpx ${YAST_PLUGIN_WFM_LIBRARY} ) +TARGET_LINK_LIBRARIES( ycpx ${RUBY_LIBRARY} ) -INSTALL(TARGETS ryast LIBRARY DESTINATION ${RUBY_ARCH_DIR} ) \ No newline at end of file +INSTALL(TARGETS ycpx LIBRARY DESTINATION ${RUBY_ARCH_DIR} ) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/ycp.rb DESTINATION ${RUBY_VENDORLIB_DIR} ) \ No newline at end of file diff --git a/src/swig/yast.i b/src/swig/yast.i index 5562714..14af158 100644 --- a/src/swig/yast.i +++ b/src/swig/yast.i @@ -1,8 +1,12 @@ -%module ryast +%module ycp %include std_string.i %include stl.i %{ /* Includes the header in the wrapper code */ +#define y2log_component "Y2Ruby" +#include + +#include #include #include #include @@ -13,24 +17,19 @@ #include #include #include - -#include -#include -#include -#include -#include -#include -#include - +#include +#include +#include #include - +#include +#include +#include #include -#define y2log_component "Y2Ruby" //static swig_type_info _swigt__p_YCPValue; - %} +%} #ifdef SWIGRUBY //%include "ruby.i" @@ -41,178 +40,43 @@ %rename("!=") "operator!="; %rename("!") "operator!"; %rename("==") "operator=="; - -%typemap(in) int YCPValue { - // TODO conver integers, and add support for lists, ah, and boleans! - switch (TYPE($1)) - { - case T_STRING: - $result = YCPString(RSTRING ($1)->ptr); - break; - case T_TRUE: - $result = YCPBoolean(true); - break; - case T_FALSE: - $result = YCPBoolean(false); - break; - case T_FIXNUM: - $result = YCPInteger(NUM2LONG($1)); - break; - case T_FLOAT: - $result = YCPFloat(NUM2DBL($1)); - break; - case T_ARRAY: - // FIXME - break; - case T_HASH: - // FIXME - break; - case T_DATA: - rb_raise( rb_eRuntimeError, "Object"); - break; - } - std::cout << TYPE($1) << std::endl; - rb_raise( rb_eRuntimeError, "Conversion of Ruby type not supported"); - $result = YCPValue(); -} - -%typemap(out) YCPValue { - // TODO - // YT_BYTEBLOCK YT_PATH YT_SYMBOL YT_LIST YT_TERM YT_MAP YT_CODE YT_RETURN YT_BREAK YT_ENTRY YT_ERROR YT_REFERENCE YT_EXTERNA - if($1->isVoid()) - { - $result = Qnil; - } - else if($1->isBoolean()) - { - $result = $1->asBoolean()->value() ? Qtrue : Qfalse; - } - else if($1->isString()) - { - $result = rb_str_new2($1->asString()->value().c_str()); - } - else if($1->isInteger()) - { - $result = INT2NUM( $1->asInteger()->value() ); - } - else if( $1->isMap() ) - { - VALUE rbhash; - rbhash = rb_hash_new(); - YCPMap map = $1->asMap(); - printf("map size %d\n", map.size()); - - for ( YCPMapIterator it = map.begin(); it != map.end(); ++it ) - { - YCPValue *key = new YCPValue(it.key()); - YCPValue *value = new YCPValue(it.value()); - VALUE rkey = SWIG_NewPointerObj(key, SWIGTYPE_p_YCPValue, 1); - VALUE rvalue = SWIG_NewPointerObj(value, SWIGTYPE_p_YCPValue, 1); - rb_hash_aset(rbhash, rkey, rvalue ); - } - $result = rbhash; - } - else if($1->isList()) - { - VALUE rblist; - rblist = rb_ary_new(); - YCPList list = $1->asList(); - printf("list size %d\n",list.size()); - for (int i=0; i < list.size(); i++) - { - YCPValue *value = new YCPValue(list.value(i)); - VALUE rvalue = SWIG_NewPointerObj(value, SWIGTYPE_p_YCPValue, 1); - rb_ary_push( rblist, rvalue); - } - $result = rblist; - } - rb_raise( rb_eRuntimeError, "Conversion of YCP type %s not supported", $1->toString().c_str() ); - $result = Qnil; -} - -//%include "y2util/RepDef.h" -%include "y2/Y2ComponentBroker.h" -%include "y2/Y2Namespace.h" -%include "y2/Y2Component.h" -%include "y2/Y2Function.h" - -%ignore SymbolEntryPtr::_nameHash; -%ignore SymbolEntry::emptyUstring; - -class SymbolEntry -{ -public: - //static UstringHash* _nameHash; - //static Ustring emptyUstring; -public: - typedef enum { - c_unspec = 0, // 0 unspecified local symbol (sets m_global = false) - c_global, // 1 unspecified global symbol (translates to c_unspec, sets m_global = true) - c_module, // 2 a module identifier - c_variable, // 3 a variable - c_reference, // 4 a reference to a variable - c_function, // 5 a defined function - c_builtin, // 6 a builtin function - c_typedef, // 7 a type - c_const, // 8 a constant (a read-only c_variable) - c_namespace, // 9 a namespace identifier - c_self, // 10 the current namespace (namespace prefix used in namespace definition) - c_predefined, // 11 a predefined namespace identifier - c_filename // 12 a filename (used in conjunction with TableEntry to store definition locations) - } category_t; -public: - // create symbol beloging to namespace (at position) - SymbolEntry (const Y2Namespace* name_space, unsigned int position, const char *name, category_t cat, constTypePtr type); - - virtual ~SymbolEntry (); - - // symbols link to the defining namespace - const Y2Namespace *nameSpace () const; - void setNamespace (const Y2Namespace *name_space); - virtual bool onlyDeclared () const { return false; } - - unsigned int position () const; - void setPosition (unsigned int position); - - bool isGlobal () const; - void setGlobal (bool global); - - bool isModule () const { return m_category == c_module; } - bool isVariable () const { return m_category == c_variable; } - bool isReference () const { return m_category == c_reference; } - bool isFunction () const { return m_category == c_function; } - bool isBuiltin () const { return m_category == c_builtin; } - bool isNamespace () const { return m_category == c_namespace; } - bool isSelf () const { return m_category == c_self; } - bool isFilename () const { return m_category == c_filename; } - bool isPredefined () const { return m_category == c_predefined; } - - bool likeNamespace () const { return isModule() || isNamespace() || isSelf(); } - - const char *name () const; - category_t category () const; - void setCategory (category_t cat); - constTypePtr type () const; - string catString () const; - void setType (constTypePtr type); - YCPValue setValue (YCPValue value); - YCPValue value () const; - - void push (); - void pop (); - - virtual string toString (bool with_type = true) const; -}; - -template < typename T > -class Ptr { - public: - T *operator->(); -}; -%template (SymbolEntryPtr) Ptr; - -%include "ycp/SymbolTable.h" - -%include "ycp/Import.h" -%include "ycp/Type.h" -%include "ycp/TypePtr.h" + +%include +%include +//%include +//%include +%include + +%nodefaultctor YCPBoolean; +%include + +//%include +//%include + +%nodefaultctor YCPString; +%include + +%nodefaultctor YCPInteger; +%include + +%nodefaultctor YCPFloat; +%include + +//%include + +%nodefaultctor YCPExternal; +%include + +%nodefaultctor YCPSymbol; +%include + +%nodefaultctor YCPTerm; +%include + +%nodefaultctor YCPByteblock; +%include + +%include +%include +//%include + diff --git a/src/swig/ycp.i b/src/swig/ycp.i new file mode 100644 index 0000000..66cb9fd --- /dev/null +++ b/src/swig/ycp.i @@ -0,0 +1,93 @@ +%module ycpx +%include std_string.i +%include stl.i +%include file.i + %{ +/* Includes the header in the wrapper code */ +#define y2log_component "Y2Ruby" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//static swig_type_info _swigt__p_YCPValue; + +%} + +%rename("+") "operator+"; +%rename("<<") "operator<<"; +%rename("!=") "operator!="; +%rename("!") "operator!"; +%rename("==") "operator=="; + +//%include + +%include + +//%include +//%include +%include + +%nodefaultctor YCPBoolean; +%include + +//%include +//%include + +%nodefaultctor YCPString; +%include + +%nodefaultctor YCPInteger; +%include + +%nodefaultctor YCPFloat; +%include + +//%include + +%nodefaultctor YCPExternal; +%include + +%nodefaultctor YCPSymbol; +%include + +%nodefaultctor YCPTerm; +%include + +%nodefaultctor YCPByteblock; +%include + +%include +%predicate YCode::isBlock(); +%predicate YCode::isStatement(); + +class YCodePtr +{ + public: + YCodePtr(const YCodePtr &); + YCodePtr(YCode*); + YCode* operator->(); +}; + +%include +//%include + +%include \ No newline at end of file diff --git a/src/swig/ycp.rb b/src/swig/ycp.rb new file mode 100644 index 0000000..2a4fc1d --- /dev/null +++ b/src/swig/ycp.rb @@ -0,0 +1,24 @@ +# -----------------------------------------------------------------------\ +# | | +# | __ __ ____ _____ ____ | +# | \ \ / /_ _/ ___|_ _|___ \ | +# | \ V / _` \___ \ | | __) | | +# | | | (_| |___) || | / __/ | +# | |_|\__,_|____/ |_| |_____| | +# | | +# | | +# | ruby language support (C) Novell Inc. | +# \----------------------------------------------------------------------/ +# +# Author: Duncan Mac-Vicar +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version +# 2 of the License, or (at your option) any later version. +# + +ENV['LD_LIBRARY_PATH'] = "/usr/lib/YaST2/plugin" + +# Load the native part (.so) +require 'ycpx' \ No newline at end of file -- 2.39.2