- fix builtins, scr
authorDuncan Mac-Vicar P <dmacvicar@suse.de>
Fri, 30 Nov 2007 15:33:28 +0000 (16:33 +0100)
committerDuncan Mac-Vicar P <dmacvicar@suse.de>
Fri, 30 Nov 2007 15:33:28 +0000 (16:33 +0100)
- add builtin introspection
- 0.3.1

CMakeLists.txt
VERSION.cmake
examples/ruby/scr.rb
package/yast2-ruby-bindings.changes
src/ruby/YCP.cc
src/ruby/yast.rb

index cde6c79..5108dfe 100644 (file)
@@ -1,5 +1,5 @@
 PROJECT(yast2-ruby-bindings)
-SET(PACKAGE "yast2-ruby-bindings")
+SET(RPMNAME "yast2-ruby-bindings")
 SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -Wall -Woverloaded-virtual" )
 SET( CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -g -O3 -Wall" )
 
index 097bf49..b9741c4 100644 (file)
@@ -1,3 +1,3 @@
 SET(VERSION_MAJOR "0")
 SET(VERSION_MINOR "3")
-SET(VERSION_PATCH "0")
+SET(VERSION_PATCH "1")
index dc027f7..2427e4e 100644 (file)
@@ -1,7 +1,7 @@
 require 'yast'
+require 'ycp/scr'
 
-m = YaST::Module.new("SCR")
-modules = m.Read(".proc.modules")
+modules = YCP::SCR::Read(".proc.modules")
 modules.each do | k, v |
   puts "#{k}:"
   v.each do | a, b |
index c512e79..6334377 100644 (file)
@@ -1,3 +1,9 @@
+-------------------------------------------------------------------
+Fri Nov 30 16:32:43 CET 2007 - dmacvicar@suse.de
+
+- fix SCR, builtin calls and add instrospection
+  for builtins 
+
 -------------------------------------------------------------------
 Wed Sep 19 16:42:35 CEST 2007 - dmacvicar@suse.de
 
index 0a1f3dd..48aa768 100644 (file)
@@ -58,7 +58,6 @@ as published by the Free Software Foundation; either version
     Data_Get_Struct(obj, Y2Namespace, po)
 
 static VALUE rb_mYaST;
-static VALUE rb_mY2ModuleProxy;
 static VALUE rb_mUi;
 static VALUE rb_mYCP;
 
@@ -76,6 +75,9 @@ typedef VALUE (ruby_method)(...);
 
 Y2Component *owned_uic = 0;
 Y2Component *owned_wfmc = 0;
+//Y2Component *owned_scr = 0;
+
+extern "C" {
 
 static
 Y2Namespace *
@@ -85,7 +87,7 @@ getNs (const char * ns_name)
   Y2Namespace *ns = import.nameSpace();
   if (ns == NULL)
   {
-    y2error ("Ruby call: Can't import namespace '%s'", ns_name);
+    y2error ("ruby call: Can't import namespace '%s'", ns_name);
   }
   else
   {
@@ -108,6 +110,20 @@ void init_wfm()
 //     }
 }
 
+// void init_scr()
+// {
+//     y2milestone("init_scr");
+// //     if (Y2WFMComponent::instance () == 0)
+// //     {
+//       y2milestone("WFM init");
+//       owned_scr = Y2ComponentBroker::createClient ("scr");
+//       if (owned_scr == 0)
+//       {
+//           y2error ("Cannot create WFM component");
+//       }
+// //     }
+// }
+
 static VALUE
 rb_init_ui( int argc, VALUE *argv, VALUE self )
 {
@@ -120,7 +136,7 @@ rb_init_ui( int argc, VALUE *argv, VALUE self )
   }
   else if (argc != 0)
   {
-    y2error ("Zero or one arguments required (ui name, default %s", ui_name);
+    y2error ("zero or one arguments required (ui name, default %s", ui_name);
     return Qnil;
   }
 
@@ -132,13 +148,13 @@ rb_init_ui( int argc, VALUE *argv, VALUE self )
     c = Y2ComponentBroker::createServer (ui_name);
     if (c == 0)
     {
-      y2error ("Cannot create component %s", ui_name);
+      y2error ("can't create component %s", ui_name);
       return Qnil;
     }
 
     if (YUIComponent::uiComponent () == 0)
     {
-      y2error ("Component %s is not a UI", ui_name);
+      y2error ("component %s is not a UI", ui_name);
       return Qnil;
     }
     else
@@ -155,59 +171,8 @@ rb_init_ui( int argc, VALUE *argv, VALUE self )
   return Qnil;
 }
 
-typedef struct brokerinfo
-{
-  Y2Component *component;
-  Y2Namespace *ns;
-}
-BrokerInfo;
-
-//  mark for garbage collection
-// NOT USED, ONLY WHEN USING DATA_WRAP_STRUCT
-void
-yast_module_mark( BrokerInfo *info )
-{}
-
-// dispose a namespace
-// NOT USED, ONLY WHEN USING DATA_WRAP_STRUCT
-void
-yast_module_free( BrokerInfo *info )
-{
-  //std::cout << "Deleting namespace." << std::endl;
-  //delete info;
-}
-
-VALUE
-yast_module_allocate( VALUE klass )
-{
-  BrokerInfo *info = new BrokerInfo;
-  return Data_Wrap_Struct( klass, yast_module_mark, RB_FINALIZER(yast_module_free), info );
-}
-
-VALUE
-yast_module_initialize( VALUE self, VALUE param_ns_name )
-{
-  Check_Type(param_ns_name, T_STRING);
-  rb_iv_set(self, "@namespace_name", param_ns_name);
-  init_wfm();
-  return self;
-}
-
-
-VALUE
-yast_module_name( VALUE self )
-{
-  return rb_iv_get(self, "@namespace_name");
-}
-
-VALUE
-yast_module_methods( VALUE self )
-{
-  return Qnil;
-}
-
 //forward declaration
-YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv );
+YCPValue _call_ycp_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv );
 
 /**
  * looks a component for a namespace
@@ -220,8 +185,8 @@ ycp_module_lookup_namespace_component(VALUE self, VALUE name)
   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("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;
@@ -237,12 +202,12 @@ 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);
+    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());
+    y2internal("namespace created from %s\n", ns->filename().c_str());
   }
   return Qtrue;
 }
@@ -258,18 +223,18 @@ ycp_module_import( VALUE self, VALUE name)
  * iterates all symbols in a namespace and yields the
  * symbol name and category
  */
-VALUE
+static 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 );
+    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());
+    y2internal("got namespace from %s\n", ns->filename().c_str());
   }
 
   for (unsigned int i=0; i < ns->symbolCount(); ++i)
@@ -283,13 +248,77 @@ ycp_module_each_symbol(VALUE self, VALUE namespace_name)
   return Qnil;
 }
 
+/**
+ * helper method
+ */
+static bool _yield_symbol_entry(const SymbolEntry & s)
+{
+  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 true;
+}
+
+/** 
+ * helper for each_builtin_symbol
+ */
+static const SymbolEntry * __symbol = 0L;
+static string __name;
+
+static
+bool __find_symbol(const SymbolEntry & s)
+{
+  if (s.name() == __name)
+  {
+    __symbol = &s;
+    return false;
+  }
+  return true;
+}
+
+/**
+ * iterates all symbols in a namespace and yields the
+ * symbol name and category
+ */
+static VALUE
+ycp_module_each_builtin_symbol(VALUE self, VALUE name)
+{
+  extern StaticDeclaration static_declarations;
+  __name = RSTRING(name)->ptr;
+  static_declarations.symbolTable()->forEach(__find_symbol);
+
+  const SymbolEntry *se = __symbol;
+  if (se == NULL)
+  {
+    y2error ("no such builtin '%s'", RSTRING(name)->ptr);
+    rb_raise( rb_eRuntimeError, "no YCP builtin %s\n", RSTRING(name)->ptr);
+  }
+
+  // convert to a YSymbol to access child symbols
+  const YSymbolEntry *ys = dynamic_cast<const YSymbolEntry *>(se);
+  if ( ys )
+  {
+    if ( ys->table() ) ys->table()->forEach(_yield_symbol_entry);
+  }
+  return Qnil;
+}
+
+static VALUE
+ycp_module_each_builtin(VALUE self)
+{
+  extern StaticDeclaration static_declarations;
+  static_declarations.symbolTable()->forEach(_yield_symbol_entry);
+  return Qnil;
+}
+
 /**
  * Forwards a ruby call to the namespace
  * First argument is the namespace
  * then function name and arguments
  */
-VALUE
-ycp_module_forward_call(int argc, VALUE *argv, VALUE self)
+static VALUE
+ycp_module_call_ycp_function(int argc, VALUE *argv, VALUE self)
 {
   y2internal("Dynamic Proxy: [%d] params\n", argc);
   VALUE symbol = argv[1];
@@ -307,18 +336,6 @@ ycp_module_forward_call(int argc, VALUE *argv, VALUE self)
 
   // get the name of the module
   //VALUE namespace_name = rb_funcall(self, rb_intern("name"), 0);
-  
-
-  // SCR
-  // this is a hack before the builtin namespaces get a uniform interface:
-  if (! strcmp (RSTRING (namespace_name)->ptr, "SCR"))
-  {
-    y2internal("Dynamic Proxy: [%s::%s] is a call to SCR\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr);
-    YCPValue res;
-    res = ycp_call_builtin( RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc, argv);
-    return ycpvalue_2_rbvalue(res);
-    //return Qnil;
-  }
 
   ycp_module_lookup_namespace_component(self, namespace_name);
 
@@ -359,8 +376,8 @@ ycp_module_forward_call(int argc, VALUE *argv, VALUE self)
 
     if (call == NULL)
     {
-      y2internal ("Cannot create function call %s\n", RSTRING(symbol_str)->ptr);
-      rb_raise( rb_eRuntimeError, "Can't create call to %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr);
+      y2internal ("cannot create function call %s\n", RSTRING(symbol_str)->ptr);
+      rb_raise( rb_eRuntimeError, "can't create call to %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr);
     }
 
     // add the parameters
@@ -373,39 +390,28 @@ ycp_module_forward_call(int argc, VALUE *argv, VALUE self)
 
     YCPValue res = call->evaluateCall ();
     delete call;
-    y2internal ("Call succeded\n");
+    y2internal ("call succeded\n");
     //y2internal ("Result: %i\n", res->asList()->size());
     return ycpvalue_2_rbvalue(res);
   }
   return Qnil;
 }
 
-YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv )
+YCPValue _call_ycp_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv )
 {
   // access directly the statically declared builtins
   extern StaticDeclaration static_declarations;
+
   string qualified_name_s = module_name + "::" + func_name;
   const char *qualified_name = qualified_name_s.c_str ();
 
-  y2milestone("Qualified name '%s'", qualified_name);
-  /*
-    this does not work across namespaces
-      TableEntry *bi_te = static_declarations.symbolTable ()->find (qualified_name);
-      if (bi_te == NULL)
-      {
-    y2error ("No such builtin %s",qualified_name);
-    return YCPNull ();
-      }
+  y2milestone("qualified name '%s', %d args", qualified_name, argc);
   
-      SymbolEntry *bi_se = bi_te->sentry ();
-      assert (bi_se != NULL);
-      assert (bi_se->isBuiltin ());
-      declaration_t bi_dt = bi_se->declaration ();
-  */
   declaration_t *bi_dt = static_declarations.findDeclaration (qualified_name);
   if (bi_dt == NULL)
   {
-    y2error ("No such builtin '%s'", qualified_name);
+    y2error ("no such builtin '%s'", qualified_name);
+    rb_raise( rb_eRuntimeError, "no YCP builtin %s\n", RSTRING(qualified_name)->ptr);
     return YCPNull ();
   }
   y2milestone("builtin '%s' found.", module_name.c_str());
@@ -417,26 +423,22 @@ YCPValue ycp_call_builtin ( const string &module_name, const string &func_name,
   // we would like to know the destination type so that we could
   // convert eg a Ruby scalar to a YCP symbol, but because the
   // builtins may be overloaded, let's say we want Any
-
   // maybe a special exceptional hack to make Path for the 1st argument?
-
   // go through the actual parameters
   int j;
-  for (j = 1; j < argc; ++j)
+  for (j = 0; j < argc; ++j)
   {
-    y2milestone("builtin param '%d'", j-1);
     // convert the value according to the expected type:
     constTypePtr param_tp = (j == 0)? Type::Path : Type::Any;
-    y2milestone("builtin param '%d' 1", j-1);
     
     // convert the first argument to a path
     YCPValue param_v;
-    if ( j == 1 )
+    // HACK SCR path conversion
+    if ( (j == 0) && (module_name == "SCR") )
       param_v = rbvalue_2_ycppath(argv[j]);
     else
       param_v = rbvalue_2_ycpvalue(argv[j] /*, param_tp */);
     
-    y2milestone("builtin param '%d' 2", j-1);
     if (param_v.isNull ())
     {
       // an error has already been reported, now refine it.
@@ -490,8 +492,21 @@ YCPValue ycp_call_builtin ( const string &module_name, const string &func_name,
   return ret_yv;
 }
 
+VALUE
+ycp_module_call_ycp_builtin( int argc, VALUE *argv, VALUE self )
+{
+  VALUE symbol = argv[1];
+  VALUE namespace_name = argv[0];
 
+  // the func name (1st argument, is a symbol
+  // lets convert it to string
+  VALUE symbol_str = rb_funcall(symbol, rb_intern("to_s"), 0);
 
+  y2internal("builtin proxy: [%s::%s] is a builtin call with %d params\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc);
+  YCPValue res;
+  res = _call_ycp_builtin( RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc-2, argv+2);
+  return ycpvalue_2_rbvalue(res);
+}
 //y2_logger_helper
 
 //y2_logger (level, comp, file, line, function, "%s", message);
@@ -514,16 +529,19 @@ rb_y2_logger( int argc, VALUE *argv, VALUE self )
   return Qnil;
 }
 
+} //extern C
+
 extern "C"
 {
   void
   Init_yastx()
   {
     YCPPathSearch::initialize ();
-
+    init_wfm();
+  
     for ( list<string>::const_iterator it = YCPPathSearch::searchListBegin (YCPPathSearch::Module); it != YCPPathSearch::searchListEnd (YCPPathSearch::Module) ; ++it )
     {
-      y2internal("%s\n", (*it).c_str() );
+      y2internal("search path %s\n", (*it).c_str() );
     }
 
     rb_mYaST = rb_define_module("YaST");
@@ -531,8 +549,12 @@ extern "C"
     //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, "call_ycp_function", RB_METHOD(ycp_module_call_ycp_function), -1);
+    rb_define_singleton_method( rb_mYCP, "call_ycp_builtin", RB_METHOD(ycp_module_call_ycp_builtin), -1);
+
     rb_define_singleton_method( rb_mYCP, "each_symbol", RB_METHOD(ycp_module_each_symbol), 1);
+    rb_define_singleton_method( rb_mYCP, "each_builtin_symbol", RB_METHOD(ycp_module_each_builtin_symbol), 1);
+    rb_define_singleton_method( rb_mYCP, "each_builtin", RB_METHOD(ycp_module_each_builtin), 0);
 
     rb_mUi = rb_define_module_under(rb_mYCP, "Ui");
     rb_define_singleton_method( rb_mUi, "init", RB_METHOD(rb_init_ui), -1);
@@ -544,3 +566,4 @@ extern "C"
     ryast_term_init(rb_mYaST);
   }
 }
+
index 444306c..8e9ff23 100644 (file)
@@ -23,20 +23,82 @@ ENV['LD_LIBRARY_PATH'] = "/usr/lib/YaST2/plugin"
 # Load the native part (.so)
 require 'yastx'
 
+module YaST
+  def y2_logger_helper(*args)
+    level = args.shift
+    
+    caller[0] =~ /(.+):(\d+):in `([^']+)'/
+    y2_logger(level,"Ruby",$1,$2.to_i,"",args[0])
+  end
+  
+  def y2debug(*args)
+    y2_logger_helper(0, args)
+  end
+  
+  def y2milestone(*args)
+    y2_logger_helper(1, args)
+  end
+  
+  def y2warning(*args)
+    y2_logger_helper(2, args)
+  end
+  
+  def y2error(*args)
+    y2_logger_helper(3, args)
+  end
+  
+  def y2security(*args)
+    y2_logger_helper(4, args)
+  end
+  
+  def y2internal(*args)
+    y2_logger_helper(5, args)
+  end
+end # module YaST
+
 module YCP
-  def self.method_missing(id, *args)
-    puts "stop"
+  
+  # inserts a builtin in the
+  # ycp module
+  def self.import_builtin(name)
+    YCP::each_builtin do |bi, cat|
+      if name == bi
+        if cat == :namespace
+          m = Module.new
+          YCP::each_builtin_symbol(bi) do |bs, scat|
+            if scat == :builtin
+              m.module_eval <<-"END"
+                def self.#{bs.downcase.to_s}(*args)
+                  return YCP::call_ycp_builtin("SCR", "#{bs.to_s}", *args)
+                end
+              END
+            end
+          end # each builtin symbol
+          YCP.const_set(bi.to_s, m)
+          return
+        else
+          raise "builtin #{bi} can't be imported (not namespace)"
+        end # if namespace
+      end
+    end # each builtin
+    raise "can't import builtin '#{bi}'"
+  end
+
+  # initialize builtins and add them to
+  # the ycp module
+  def self.init_builtins
+
   end
 
   def self.add_ycp_module(mname)
-    puts "import #{mname}"
+    #y2internal("tryng to add 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)
-            return YCP::forward_call("#{mname}", :#{sname}, *args)
+            return YCP::call_ycp_function("#{mname}", :#{sname}, *args)
           end
         END
       end # if function
@@ -45,12 +107,27 @@ module YCP
   end
 end
 
+YCP::init_builtins
+
 module Kernel
   alias require_ require 
   def require(name)
     if name =~ /^ycp\/(.+)$/
       ycpns = $1
-      YCP::add_ycp_module(ycpns.capitalize)
+      
+      YCP::each_builtin do |bi, cat|
+        if bi.downcase == ycpns.downcase
+          YCP::import_builtin(bi)
+          return
+        end
+      end
+
+      begin
+        YCP::add_ycp_module(ycpns.upcase)
+      rescue RuntimeError => e
+        puts e
+        YCP::add_ycp_module(ycpns.capitalize)
+      end
       return true
     end
     return require_(name)
@@ -103,7 +180,6 @@ module YCP
 end
 
 module YaST
-
   class TermBuilder
     # blank slate
     instance_methods.each { |m| undef_method m unless (m =~ /^__|instance_eval$/)}
@@ -141,36 +217,4 @@ module YaST
     end
     
   end
-
-  def y2_logger_helper(*args)
-    level = args.shift
-    
-    caller[0] =~ /(.+):(\d+):in `([^']+)'/
-    y2_logger(level,"Ruby",$1,$2.to_i,"",args[0])
-  end
-  
-  def y2debug(*args)
-    y2_logger_helper(0, args)
-  end
-  
-  def y2milestone(*args)
-    y2_logger_helper(1, args)
-  end
-  
-  def y2warning(*args)
-    y2_logger_helper(2, args)
-  end
-  
-  def y2error(*args)
-    y2_logger_helper(3, args)
-  end
-  
-  def y2security(*args)
-    y2_logger_helper(4, args)
-  end
-  
-  def y2internal(*args)
-    y2_logger_helper(5, args)
-  end
-  
 end # module YaST
\ No newline at end of file