From 6cb658d6289304dec2e0d27bafbf215ba270bba9 Mon Sep 17 00:00:00 2001 From: dmacvicar Date: Wed, 19 Sep 2007 15:50:57 +0000 Subject: [PATCH] - Lot of fixes and support for the UI!!! git-svn-id: http://svn.opensuse.org/svn/yast/trunk/ruby-bindings@40969 e0cc52ee-31ee-0310-8b87-e83c4596d67c --- CMakeLists.txt | 98 ++++++ MAINTAINER | 2 + README | 17 + RPMNAME | 1 + TODO | 6 + VERSION.cmake | 3 + cmake/modules/FindRuby.cmake | 84 +++++ cmake/modules/FindYast.cmake | 53 +++ examples/ruby/Bar.rb | 8 + examples/ruby/Foo.rb | 0 examples/ruby/libycp.rb | 45 +++ examples/ruby/logger.rb | 5 + examples/ruby/module-arch.rb | 6 + examples/ruby/module-storage.rb | 7 + examples/ruby/module-timezone.rb | 12 + examples/ruby/ruby_from_ycp.ycp | 13 + examples/ruby/ruby_from_ycp_2.ycp | 14 + examples/ruby/scr.rb | 10 + examples/ruby/scr.ycp | 12 + examples/ruby/ui.rb | 22 ++ modules/MyModule.ycp | 14 + package/yast2-ruby-bindings.changes | 18 + src/CMakeLists.txt | 2 + src/ruby/CMakeLists.txt | 53 +++ src/ruby/Makefile.am | 93 +++++ src/ruby/RubyLogger.cc | 52 +++ src/ruby/RubyLogger.h | 44 +++ src/ruby/Y2CCRuby.cc | 65 ++++ src/ruby/Y2CCRuby.h | 77 ++++ src/ruby/Y2RubyComponent.cc | 75 ++++ src/ruby/Y2RubyComponent.h | 76 ++++ src/ruby/Y2RubyTypeConv.cc | 203 +++++++++++ src/ruby/Y2RubyTypeConv.h | 50 +++ src/ruby/Y2RubyTypePath.cc | 75 ++++ src/ruby/Y2RubyTypePath.h | 30 ++ src/ruby/Y2RubyTypeTerm.cc | 171 +++++++++ src/ruby/Y2RubyTypeTerm.h | 36 ++ src/ruby/YCP.cc | 473 +++++++++++++++++++++++++ src/ruby/YCP.rb | 520 ++++++++++++++++++++++++++++ src/ruby/YRuby.cc | 173 +++++++++ src/ruby/YRuby.h | 107 ++++++ src/ruby/YRubyNamespace.cc | 314 +++++++++++++++++ src/ruby/YRubyNamespace.h | 58 ++++ src/ruby/YaPI.pm.in | 246 +++++++++++++ src/ruby/yast.rb | 141 ++++++++ src/swig/CMakeLists.txt | 30 ++ src/swig/yast.i | 218 ++++++++++++ yast2-ruby-bindings.spec.in | 57 +++ 48 files changed, 3889 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 MAINTAINER create mode 100644 README create mode 100644 RPMNAME create mode 100644 TODO create mode 100644 VERSION.cmake create mode 100644 cmake/modules/FindRuby.cmake create mode 100644 cmake/modules/FindYast.cmake create mode 100644 examples/ruby/Bar.rb create mode 100644 examples/ruby/Foo.rb create mode 100644 examples/ruby/libycp.rb create mode 100644 examples/ruby/logger.rb create mode 100644 examples/ruby/module-arch.rb create mode 100644 examples/ruby/module-storage.rb create mode 100644 examples/ruby/module-timezone.rb create mode 100644 examples/ruby/ruby_from_ycp.ycp create mode 100644 examples/ruby/ruby_from_ycp_2.ycp create mode 100644 examples/ruby/scr.rb create mode 100644 examples/ruby/scr.ycp create mode 100644 examples/ruby/ui.rb create mode 100644 modules/MyModule.ycp create mode 100644 package/yast2-ruby-bindings.changes create mode 100644 src/CMakeLists.txt create mode 100644 src/ruby/CMakeLists.txt create mode 100644 src/ruby/Makefile.am create mode 100644 src/ruby/RubyLogger.cc create mode 100644 src/ruby/RubyLogger.h create mode 100644 src/ruby/Y2CCRuby.cc create mode 100644 src/ruby/Y2CCRuby.h create mode 100644 src/ruby/Y2RubyComponent.cc create mode 100644 src/ruby/Y2RubyComponent.h create mode 100644 src/ruby/Y2RubyTypeConv.cc create mode 100644 src/ruby/Y2RubyTypeConv.h create mode 100644 src/ruby/Y2RubyTypePath.cc create mode 100644 src/ruby/Y2RubyTypePath.h create mode 100644 src/ruby/Y2RubyTypeTerm.cc create mode 100644 src/ruby/Y2RubyTypeTerm.h create mode 100644 src/ruby/YCP.cc create mode 100644 src/ruby/YCP.rb create mode 100644 src/ruby/YRuby.cc create mode 100644 src/ruby/YRuby.h create mode 100644 src/ruby/YRubyNamespace.cc create mode 100644 src/ruby/YRubyNamespace.h create mode 100644 src/ruby/YaPI.pm.in create mode 100644 src/ruby/yast.rb create mode 100644 src/swig/CMakeLists.txt create mode 100644 src/swig/yast.i create mode 100644 yast2-ruby-bindings.spec.in diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a61d065 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,98 @@ +PROJECT(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" ) + +# Library +IF ( DEFINED LIB ) + SET ( LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${LIB}" ) +ELSE ( DEFINED LIB ) + IF (CMAKE_SIZEOF_VOID_P MATCHES "8") + SET( LIB_SUFFIX "64" ) + ENDIF(CMAKE_SIZEOF_VOID_P MATCHES "8") + SET ( LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" ) +ENDIF ( DEFINED LIB ) +MESSAGE(STATUS "Libraries will be installed in ${LIB_INSTALL_DIR}" ) + +# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked +SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) +#SET(CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/cmake/Modules ${CMAKE_MODULE_PATH}) + +SET( PACKAGE "yast2-ruby-bindings" ) +INCLUDE(${CMAKE_SOURCE_DIR}/VERSION.cmake) +SET ( VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" ) + +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Language Bindings for YaST") +SET(CPACK_PACKAGE_VENDOR "Novell Inc.") +#SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/ReadMe.txt") +#SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt") +SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) +SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR}) +SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH}) + +SET( CPACK_GENERATOR "TBZ2") +SET( CPACK_SOURCE_GENERATOR "TBZ2") +SET( CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE}-${VERSION}" ) + +# The following components are regex's to match anywhere (unless anchored) +# in absolute path + filename to find files or directories to be excluded +# from source tarball. +SET (CPACK_SOURCE_IGNORE_FILES +"/CVS/;/.svn/;/.libs/;/.deps/;/.git/;.swp$;.#;/#;/build/" +"~$" +"\\\\.cvsignore$" +"/package" +"Makefile\\\\.in$" +) + +INCLUDE(CPack) + +#FIND_PACKAGE(SWIG REQUIRED) + +FIND_PROGRAM(SWIG_EXECUTABLE + NAMES swig-1.3 swig + PATHS ${SWIG_DIR} ${SWIG_DIR}/.. ${SWIG_DIR}/../../bin /usr/bin /usr/local/bin ${CMAKE_INSTALL_PREFIX}/bin +) + +IF ( NOT SWIG_EXECUTABLE ) + MESSAGE( FATAL "SWIG not found." ) +ELSE ( NOT SWIG_EXECUTABLE ) + MESSAGE( STATUS "SWIG found at ${SWIG_EXECUTABLE}" ) +ENDIF ( NOT SWIG_EXECUTABLE ) + +FIND_PACKAGE(Yast REQUIRED) +FIND_PACKAGE(Ruby REQUIRED) + +#RUBY_RUBY_LIB_PATH +MESSAGE( STATUS "Ruby vendor arch dir: ${RUBY_VENDORARCH_DIR}" ) + +#################################################################### +# RPM SPEC # +#################################################################### +MESSAGE(STATUS "Writing spec file...") +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/${PACKAGE}.spec.in ${CMAKE_BINARY_DIR}/package/${PACKAGE}.spec @ONLY) + +ADD_SUBDIRECTORY(src) + +INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +ADD_CUSTOM_TARGET( svncheck + COMMAND cd $(CMAKE_SOURCE_DIR) && ! LC_ALL=C svn status --show-updates --quiet | grep -v '^Status against revision' +) + +SET( AUTOBUILD_COMMAND + COMMAND ${CMAKE_MAKE_PROGRAM} package_source + COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2 ${CMAKE_BINARY_DIR}/package + COMMAND ${CMAKE_COMMAND} -E remove ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2 + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/package/${PACKAGE}.changes" "${CMAKE_BINARY_DIR}/package/${PACKAGE}.changes" +) + +ADD_CUSTOM_TARGET( srcpackage_local + ${AUTOBUILD_COMMAND} +) + +ADD_CUSTOM_TARGET( srcpackage + COMMAND ${CMAKE_MAKE_PROGRAM} svncheck + ${AUTOBUILD_COMMAND} +) + diff --git a/MAINTAINER b/MAINTAINER new file mode 100644 index 0000000..e0dbd2d --- /dev/null +++ b/MAINTAINER @@ -0,0 +1,2 @@ +Duncan Mac-Vicar + diff --git a/README b/README new file mode 100644 index 0000000..93ff4bc --- /dev/null +++ b/README @@ -0,0 +1,17 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ V / _` \___ \ | | __) | | +| | | (_| |___) || | / __/ | +| |_|\__,_|____/ |_| |_____| | +| | +| | +| ruby language support (C) Novell Inc. | +\----------------------------------------------------------------------/ + +Author: Duncan Mac-Vicar + +Based on yast2-perl-bindings by + Martin Vidner + Stefan Hundhammer diff --git a/RPMNAME b/RPMNAME new file mode 100644 index 0000000..57030e1 --- /dev/null +++ b/RPMNAME @@ -0,0 +1 @@ +yast2-ruby-bindings diff --git a/TODO b/TODO new file mode 100644 index 0000000..b9c5e92 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +What is missing. + +- UI support +- Conversion of some types from ruby to YCP like hash and arrays +- handling of abort signal from the interpreter. +- implement y2log functions diff --git a/VERSION.cmake b/VERSION.cmake new file mode 100644 index 0000000..672b177 --- /dev/null +++ b/VERSION.cmake @@ -0,0 +1,3 @@ +SET(VERSION_MAJOR "0") +SET(VERSION_MINOR "2") +SET(VERSION_PATCH "0") \ No newline at end of file diff --git a/cmake/modules/FindRuby.cmake b/cmake/modules/FindRuby.cmake new file mode 100644 index 0000000..0ee5da2 --- /dev/null +++ b/cmake/modules/FindRuby.cmake @@ -0,0 +1,84 @@ +# - Find Ruby +# This module finds if Ruby is installed and determines where the include files +# and libraries are. It also determines what the name of the library is. This +# code sets the following variables: +# +# RUBY_INCLUDE_PATH = path to where ruby.h can be found +# RUBY_EXECUTABLE = full path to the ruby binary + +# Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. +# See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + +if(RUBY_LIBRARY AND RUBY_INCLUDE_PATH) + # Already in cache, be silent + set(RUBY_FIND_QUIETLY TRUE) +endif (RUBY_LIBRARY AND RUBY_INCLUDE_PATH) + +# RUBY_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'` +# RUBY_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'` +# RUBY_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'` +# RUBY_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'` +# RUBY_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'` + +FIND_PROGRAM(RUBY_EXECUTABLE NAMES ruby ruby1.8 ruby18 ) + +EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['archdir']" + OUTPUT_VARIABLE RUBY_ARCH_DIR) + +EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['libdir']" + OUTPUT_VARIABLE RUBY_POSSIBLE_LIB_PATH) + +EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['rubylibdir']" + OUTPUT_VARIABLE RUBY_RUBY_LIB_PATH) + +# site_ruby +EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['sitearchdir']" + OUTPUT_VARIABLE RUBY_SITEARCH_DIR) + +EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['sitelibdir']" + OUTPUT_VARIABLE RUBY_SITELIB_DIR) + + +# vendor_ruby +EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r vendor-specific -e "print '-rvendor-specific'" + OUTPUT_VARIABLE RUBY_VENDOR_ARG) + +IF(RUBY_VENDOR_ARG) + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['vendorarchdir']" + OUTPUT_VARIABLE RUBY_VENDORARCH_DIR) + + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['vendorlibdir']" + OUTPUT_VARIABLE RUBY_VENDORLIB_DIR) +ELSE(RUBY_VENDOR_ARG) + # fall back to site*dir + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['sitearchdir']" + OUTPUT_VARIABLE RUBY_VENDORARCH_DIR) + + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['sitelibdir']" + OUTPUT_VARIABLE RUBY_VENDORLIB_DIR) +ENDIF(RUBY_VENDOR_ARG) + +# this is not needed if you use "print" inside the ruby statements +# remove the new lines from the output by replacing them with empty strings +#STRING(REPLACE "\n" "" RUBY_ARCH_DIR "${RUBY_ARCH_DIR}") +#STRING(REPLACE "\n" "" RUBY_POSSIBLE_LIB_PATH "${RUBY_POSSIBLE_LIB_PATH}") +#STRING(REPLACE "\n" "" RUBY_RUBY_LIB_PATH "${RUBY_RUBY_LIB_PATH}") + + +FIND_PATH(RUBY_INCLUDE_PATH + NAMES ruby.h + PATHS + ${RUBY_ARCH_DIR} + /usr/lib/ruby/1.8/i586-linux-gnu/ ) + +FIND_LIBRARY(RUBY_LIBRARY + NAMES ruby ruby1.8 + PATHS ${RUBY_POSSIBLE_LIB_PATH} + ) + +MARK_AS_ADVANCED( + RUBY_EXECUTABLE + RUBY_LIBRARY + RUBY_INCLUDE_PATH + ) diff --git a/cmake/modules/FindYast.cmake b/cmake/modules/FindYast.cmake new file mode 100644 index 0000000..a9de452 --- /dev/null +++ b/cmake/modules/FindYast.cmake @@ -0,0 +1,53 @@ + +if(YAST_INCLUDE_DIR AND YAST_LIBRARY AND YAST_YCP_LIBRARY) + # Already in cache, be silent + set(YAST_FIND_QUIETLY TRUE) +endif(YAST_INCLUDE_DIR AND YAST_LIBRARY AND YAST_YCP_LIBRARY) + +set(YAST_LIBRARY) +set(YAST_INCLUDE_DIR) +set(YAST_YCP_LIBRARY) + +FIND_PATH(YAST_INCLUDE_DIR Y2.h + ${CMAKE_INSTALL_PREFIX}/include/YaST2 + /usr/include/YaST2 + /usr/local/include/YaST2 +) + +SET(YAST_PLUGIN_DIR ${LIB_INSTALL_DIR}/YaST2/plugin) + +FIND_LIBRARY(YAST_LIBRARY NAMES y2 + PATHS + ${LIB_INSTALL_DIR} + /usr/local/lib +) + +FIND_LIBRARY(YAST_YCP_LIBRARY NAMES ycp + PATHS + ${LIB_INSTALL_DIR} + /usr/local/lib +) + +FIND_LIBRARY(YAST_PLUGIN_WFM_LIBRARY NAMES py2wfm + PATHS + ${YAST_PLUGIN_DIR} + /usr/lib + /usr/local/lib +) + +FIND_LIBRARY(YAST_PLUGIN_SCR_LIBRARY NAMES py2scr + PATHS + ${YAST_PLUGIN_DIR} + ${LIB_INSTALL_DIR} + /usr/local/lib +) + +if(YAST_INCLUDE_DIR AND YAST_LIBRARY AND YAST_YCP_LIBRARY) + MESSAGE( STATUS "YaST2 found: includes in ${YAST_INCLUDE_DIR}, library in ${YAST_LIBRARY}") + MESSAGE( STATUS " plugins in ${YAST_PLUGIN_DIR}") + set(YAST_FOUND TRUE) +else(YAST_INCLUDE_DIR AND YAST_LIBRARY AND YAST_YCP_LIBRARY) + MESSAGE( STATUS "YaST2 not found") +endif(YAST_INCLUDE_DIR AND YAST_LIBRARY AND YAST_YCP_LIBRARY) + +MARK_AS_ADVANCED(YAST_INCLUDE_DIR YAST_LIBRARY YAST_YCP_LIBRARY YAST_PLUGIN_WFM_LIBRARY ${YAST_PLUGIN_DIR}) \ No newline at end of file diff --git a/examples/ruby/Bar.rb b/examples/ruby/Bar.rb new file mode 100644 index 0000000..e2d3ec1 --- /dev/null +++ b/examples/ruby/Bar.rb @@ -0,0 +1,8 @@ +require 'yast' + +module Bar + def self.try + m = YaST::Module.new("SCR") + return m.Execute(".target.bash", "firefox").class.to_s + end +end diff --git a/examples/ruby/Foo.rb b/examples/ruby/Foo.rb new file mode 100644 index 0000000..e69de29 diff --git a/examples/ruby/libycp.rb b/examples/ruby/libycp.rb new file mode 100644 index 0000000..bbaf9a8 --- /dev/null +++ b/examples/ruby/libycp.rb @@ -0,0 +1,45 @@ +require 'ryast' +include Ryast + +def get_ns(name) + import = Import.new(name) + ns = import.name_space + puts ns.filename + #ns.initialize + + return ns +end + +component = Y2ComponentBroker.get_namespace_component("Arch"); +#puts component.methods +#Y2Namespace *ns = c->import(RSTRING (namespace_name)->ptr); +nsname = "Arch" +fncname = "sparc32" +ns = get_ns(nsname) +#/**/ +#t = Type.from_signature("bool()") +#puts t +sym = ns.table.find(fncname); +puts sym.class +if (sym.nil?) + raise ("No such symbol #{nsname}::#{fncname}") +elsif (sym.sentry.is_variable or sym.sentry.reference? ) + # set the variable + #ret_yv = YCP_getset_variable (aTHX_ ns_name, sym_te->sentry (), args); +else + fnccall = ns.create_function_call(fncname, nil) + if fnccall.nil? + raise("No such function #{nsname}::#{fncname}") + end +end +exit + +h = ns.lookup_symbol("sparc32") +puts h.class +exit +function = ns.create_function_call("sparc32",0) +#call->appendParameter (v); +function.finish_parameters +res = function.evaluate_call +puts res +exit diff --git a/examples/ruby/logger.rb b/examples/ruby/logger.rb new file mode 100644 index 0000000..06f9125 --- /dev/null +++ b/examples/ruby/logger.rb @@ -0,0 +1,5 @@ +require 'yast' +include YaST +#ui = YaST::Module.new("UI") + +y2milestone("Hello") \ No newline at end of file diff --git a/examples/ruby/module-arch.rb b/examples/ruby/module-arch.rb new file mode 100644 index 0000000..a813d97 --- /dev/null +++ b/examples/ruby/module-arch.rb @@ -0,0 +1,6 @@ +require 'yast' + +m = YaST::Module.new("Arch") +puts m.sparc32 +puts m.arch_short +puts m.is_xen diff --git a/examples/ruby/module-storage.rb b/examples/ruby/module-storage.rb new file mode 100644 index 0000000..a47825e --- /dev/null +++ b/examples/ruby/module-storage.rb @@ -0,0 +1,7 @@ +require 'yast' + +m = YaST::Module.new("Storage") +dp = m.GetDiskPartition("/dev/sda1") +dp.each do | key, value | + puts "#{key} #{value}" +end \ No newline at end of file diff --git a/examples/ruby/module-timezone.rb b/examples/ruby/module-timezone.rb new file mode 100644 index 0000000..09fca27 --- /dev/null +++ b/examples/ruby/module-timezone.rb @@ -0,0 +1,12 @@ +require 'yast' + +m = YaST::Module.new("Timezone") +zonemap = m.get_zonemap() +puts zonemap.class +zonemap.each do | element | + element.each do | key, value | + value.each do | k, v | + puts "#{k} #{v}" + end + end +end diff --git a/examples/ruby/ruby_from_ycp.ycp b/examples/ruby/ruby_from_ycp.ycp new file mode 100644 index 0000000..b61bd3c --- /dev/null +++ b/examples/ruby/ruby_from_ycp.ycp @@ -0,0 +1,13 @@ + +{ + import "Duncan"; + string result = (string) multiply_by_eight(10); + UI::OpenDialog( + `VBox( + `Label(result), + `PushButton("OK") + ) + ); + UI::UserInput(); + UI::CloseDialog(); +} \ No newline at end of file diff --git a/examples/ruby/ruby_from_ycp_2.ycp b/examples/ruby/ruby_from_ycp_2.ycp new file mode 100644 index 0000000..733d4d9 --- /dev/null +++ b/examples/ruby/ruby_from_ycp_2.ycp @@ -0,0 +1,14 @@ + +{ + import "Foo"; + //integer result = (integer) Foo::multiply_by_eight(6); + integer result2 = (integer) Foo::sum(2,3); + UI::OpenDialog( + `VBox( + `Label(sformat("%1", result2)), + `PushButton("OK") + ) + ); + UI::UserInput(); + UI::CloseDialog(); +} \ No newline at end of file diff --git a/examples/ruby/scr.rb b/examples/ruby/scr.rb new file mode 100644 index 0000000..dc027f7 --- /dev/null +++ b/examples/ruby/scr.rb @@ -0,0 +1,10 @@ +require 'yast' + +m = YaST::Module.new("SCR") +modules = m.Read(".proc.modules") +modules.each do | k, v | + puts "#{k}:" + v.each do | a, b | + puts " #{a} - #{b}" + end +end \ No newline at end of file diff --git a/examples/ruby/scr.ycp b/examples/ruby/scr.ycp new file mode 100644 index 0000000..a51ec9d --- /dev/null +++ b/examples/ruby/scr.ycp @@ -0,0 +1,12 @@ +{ + import "Bar"; + string result = (string) Bar::try(); + UI::OpenDialog( + `VBox( + `Label(result), + `PushButton("OK") + ) + ); + UI::UserInput(); + UI::CloseDialog(); +} \ No newline at end of file diff --git a/examples/ruby/ui.rb b/examples/ruby/ui.rb new file mode 100644 index 0000000..7f7fcad --- /dev/null +++ b/examples/ruby/ui.rb @@ -0,0 +1,22 @@ +require 'yast' +ui = YaST::Module.new("UI") +YaST::Ui::init("qt") +include YaST::Ui + +t = HBox( Label("Welcome to Ruby!"), PushButton("Push me") ) + +puts "#{t.to_s} #{t.class}" + +ui.OpenDialog(t) +ui.UserInput() + +# You can also use downcase, as the symbols are aliased +t = hbox( label("Welcome to Ruby!"), pushbutton("Push me") ) + +puts "#{t.to_s} #{t.class}" + +ui.OpenDialog(t) +ui.UserInput() + + +exit \ No newline at end of file diff --git a/modules/MyModule.ycp b/modules/MyModule.ycp new file mode 100644 index 0000000..17fb7f1 --- /dev/null +++ b/modules/MyModule.ycp @@ -0,0 +1,14 @@ +{ + module "MyModule"; + + global void nothing() + { + y2milestone("doing nothing, returning nothing"); + } + + global integer half( integer value ) + { + return value / 2; + } +} + \ No newline at end of file diff --git a/package/yast2-ruby-bindings.changes b/package/yast2-ruby-bindings.changes new file mode 100644 index 0000000..c512e79 --- /dev/null +++ b/package/yast2-ruby-bindings.changes @@ -0,0 +1,18 @@ +------------------------------------------------------------------- +Wed Sep 19 16:42:35 CEST 2007 - dmacvicar@suse.de + +- Lot of improvements, examples and + support for the YaST UI +- 0.2.0 + +------------------------------------------------------------------- +Thu Aug 9 12:01:39 CEST 2007 - dmacvicar@suse.de + +- Fix build on 64 bits +- Use ruby vendor arch dir + +------------------------------------------------------------------- +Mon Aug 6 13:33:43 CEST 2007 - dmacvicar@suse.de + +- Initial release 0.1.0 + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..2a3b5fa --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,2 @@ +#ADD_SUBDIRECTORY(swig) +ADD_SUBDIRECTORY(ruby) \ No newline at end of file diff --git a/src/ruby/CMakeLists.txt b/src/ruby/CMakeLists.txt new file mode 100644 index 0000000..11e9caf --- /dev/null +++ b/src/ruby/CMakeLists.txt @@ -0,0 +1,53 @@ + +ADD_DEFINITIONS(-DY2LOG=\\\"Ruby\\\") + +SET(yast_ruby_module_SRCS + YCP.cc + Y2RubyTypeConv.cc + RubyLogger.cc + RubyLogger.h +) + +SET(ruby_yast_plugin_SRCS + RubyLogger.cc + Y2CCRuby.cc + Y2RubyComponent.cc + YRuby.cc + YRubyNamespace.cc + Y2RubyTypeConv.cc + Y2RubyTypePath.cc + Y2RubyTypeTerm.cc +) + +SET(ruby_yast_plugin_HEADERS + RubyLogger.h + Y2CCRuby.h + Y2RubyComponent.h + YRuby.h + YRubyNamespace.h + Y2RubyTypePath.h + Y2RubyTypeTerm.h +) + +INCLUDE_DIRECTORIES( ${RUBY_INCLUDE_PATH} ) +INCLUDE_DIRECTORIES( ${YAST_INCLUDE_DIR} ) + +ADD_LIBRARY( yastx SHARED ${yast_ruby_module_SRCS}) +SET_TARGET_PROPERTIES( yastx PROPERTIES PREFIX "" ) +TARGET_LINK_LIBRARIES( yastx ${YAST_LIBRARY} ) +TARGET_LINK_LIBRARIES( yastx ${YAST_YCP_LIBRARY} ) +TARGET_LINK_LIBRARIES( yastx ${YAST_PLUGIN_WFM_LIBRARY} ) +TARGET_LINK_LIBRARIES( yastx ${YAST_PLUGIN_SCR_LIBRARY} ) +TARGET_LINK_LIBRARIES( yastx ${RUBY_LIBRARY} ) +INSTALL(TARGETS yastx LIBRARY DESTINATION ${RUBY_VENDORARCH_DIR} ) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/yast.rb DESTINATION ${RUBY_VENDORLIB_DIR} ) + +ADD_LIBRARY( py2lang_ruby SHARED ${ruby_yast_plugin_SRCS}) +TARGET_LINK_LIBRARIES( py2lang_ruby ${YAST_LIBRARY} ) +TARGET_LINK_LIBRARIES( py2lang_ruby ${YAST_YCP_LIBRARY} ) +TARGET_LINK_LIBRARIES( py2lang_ruby ${YAST_PLUGIN_WFM_LIBRARY} ) +TARGET_LINK_LIBRARIES( py2lang_ruby ${RUBY_LIBRARY} ) +INSTALL(TARGETS py2lang_ruby LIBRARY DESTINATION ${YAST_PLUGIN_DIR} ) + +#SET_TARGET_PROPERTIES( y2lang_ruby PROPERTIES PREFIX "" ) \ No newline at end of file diff --git a/src/ruby/Makefile.am b/src/ruby/Makefile.am new file mode 100644 index 0000000..77063ad --- /dev/null +++ b/src/ruby/Makefile.am @@ -0,0 +1,93 @@ +# +# Makefile.am for perl-bindings/src +# + +AM_CXXFLAGS = -DY2LOG=\"Perl\" -DMODULEDIR=\"$(moduledir)\" + +MY_PERL_VENDORARCH = $(subst /usr,$(prefix),$(PERL_VENDORARCH)) +perlpmdir = $(MY_PERL_VENDORARCH)/YaST +perlsodir = $(MY_PERL_VENDORARCH)/auto/YaST/YCP + +perlpm_DATA = YCP.pm + +# plugin, libtool forces 'lib' prefix +plugin_LTLIBRARIES = libpy2lang_perl.la +noinst_LTLIBRARIES = liby2lang_perl.la +perlso_LTLIBRARIES = libYCP.la + +# binary part of the Perl module +libYCP_la_SOURCES = \ + $(liby2lang_perl_la_SOURCES) \ + YCP.cc \ + PerlLogger.cc PerlLogger.h + + +# are there enough yast libraries? +# check with y2base, integrate them like y2pm does +# Originally, of the py2* there was only py2plugin here +# with the assumption that it would bring in the other plugins. +# But it does not work. +libYCP_la_LDFLAGS = $(PERL_LDFLAGS) \ + -L$(libdir) -L$(plugindir) \ + -Xlinker --whole-archive \ + -lpy2scr \ + -lpy2wfm \ + -lscr -lyui \ + -lycp -ly2 \ + -Xlinker --no-whole-archive \ + ${ZYPP_LIBS} -ly2util \ + -version-info 2:0 + + +libpy2lang_perl_la_LDFLAGS = -version-info 2:0 + +liby2lang_perl_la_LDFLAGS = -version-info 2:0 + + +# the yast libraries are apparently necessary when we're loaded by perl. +libpy2lang_perl_la_LIBADD = $(PERL_LDFLAGS) \ + -L$(libdir) -L$(plugindir) \ + -lycp -ly2 ${ZYPP_LIBS} -ly2util +#libpy2lang_perl_la_LIBADD = $(PERL_LDFLAGS) + +liby2lang_perl_la_LIBADD = $(PERL_LDFLAGS) + + +liby2lang_perl_la_SOURCES = \ + YPerl.cc YPerl.h \ + perlxsi.c + +# Auto-generated stub for dynamic loading of Perl modules. +# And also register the interface to the YCP module +## which is linked in already and won't be in the standard Perl location. +# +# This results in a linker warning: +# *** Warning: Linking the shared library libpy2lang_perl.la against the +# *** static library /usr/lib/perl5/.../DynaLoader.a is not portable! +# +# According to mls@suse.de this warning can safely be disregarded: +# The SuSE DynaLoader is compiled with -fPIC for just this situation. +# +# -- sh@suse.de 2003-07-24 +perlxsi.c: + perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c -std +# See "man perlembed" + + +# the plugin adds the liby2 component interface + +libpy2lang_perl_la_SOURCES = \ + $(liby2lang_perl_la_SOURCES) \ + Y2CCPerl.cc Y2CCPerl.h \ + YPerlNamespace.cc YPerlNamespace.h \ + Y2PerlComponent.cc Y2PerlComponent.h + +CLEANFILES = \ + perlxsi.c + +INCLUDES = -I$(srcdir)/include -I$(includedir) ${ZYPP_CFLAGS} + +# generated from YaPI.pm.in by configure +nodist_module_DATA = YaPI.pm + +EXTRA_DIST = $(perlpm_DATA) $(module_DATA) diff --git a/src/ruby/RubyLogger.cc b/src/ruby/RubyLogger.cc new file mode 100644 index 0000000..e6a168c --- /dev/null +++ b/src/ruby/RubyLogger.cc @@ -0,0 +1,52 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#include "RubyLogger.h" +#include + +extern ExecutionEnvironment ee; + +void +RubyLogger::error (string error_message) +{ + y2_logger (LOG_ERROR,"Ruby",ee.filename ().c_str () + ,ee.linenumber (),"","%s", error_message.c_str ()); +} + + +void +RubyLogger::warning (string warning_message) +{ + y2_logger (LOG_ERROR,"Ruby",ee.filename ().c_str () + ,ee.linenumber (),"","%s", warning_message.c_str ()); +} + +RubyLogger* +RubyLogger::instance () +{ + if ( ! m_rubylogger ) + { + m_rubylogger = new RubyLogger (); + } + return m_rubylogger; +} + +RubyLogger* RubyLogger::m_rubylogger = NULL; diff --git a/src/ruby/RubyLogger.h b/src/ruby/RubyLogger.h new file mode 100644 index 0000000..af82b0f --- /dev/null +++ b/src/ruby/RubyLogger.h @@ -0,0 +1,44 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#ifndef RubyLogger_h +#define RubyLogger_h + +#include "ycp/y2log.h" + +/** + * @short A class to provide logging for Ruby bindings errors and warning + */ +class RubyLogger : public Logger +{ + static RubyLogger* m_rubylogger; + +public: + void error (string message); + void warning (string message); + + static RubyLogger* instance (); +}; + +#endif // ifndef RubyLogger_h + + +// EOF diff --git a/src/ruby/Y2CCRuby.cc b/src/ruby/Y2CCRuby.cc new file mode 100644 index 0000000..3dcefe6 --- /dev/null +++ b/src/ruby/Y2CCRuby.cc @@ -0,0 +1,65 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#include "Y2CCRuby.h" +#include +#define y2log_component "Y2Ruby" +#include + +// This is very important: We create one global variable of +// Y2CCRuby. Its constructor will register it automatically to +// the Y2ComponentBroker, so that will be able to find it. +// This all happens before main() is called! + +Y2CCRuby g_y2ccruby; + +Y2Component *Y2CCRuby::provideNamespace (const char *name) +{ + y2debug ("Y2CCRuby::provideNamespace %s", name); + if (strcmp (name, "Ruby") == 0) + { + // low level functions + + // leave implementation to later + return 0; + } + else + { + // is there a ruby module? + // must be the same in Y2CCRuby and Y2RubyComponent + string module = YCPPathSearch::find (YCPPathSearch::Module, string (name) + ".rb"); + + if (!module.empty ()) + { + y2milestone("Find module result: '%s'", module.c_str()); + if (!cruby) + { + y2milestone("new ruby component"); + cruby = new Y2RubyComponent(); + } + y2milestone("returning existing ruby component"); + return cruby; + } + + // let someone else try creating the namespace + return 0; + } +} diff --git a/src/ruby/Y2CCRuby.h b/src/ruby/Y2CCRuby.h new file mode 100644 index 0000000..7db90ec --- /dev/null +++ b/src/ruby/Y2CCRuby.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#ifndef _Y2CCRuby_h +#define _Y2CCRuby_h + +#include "Y2RubyComponent.h" + +/** + * @short Y2ComponentCreator that creates Ruby-from-YCP bindings. + * + * A Y2ComponentCreator is an object that can create components. + * It receives a component name and - if it knows how to create + * such a component - returns a newly created component of this + * type. Y2CCRuby can create components with the name "Ruby". + */ +class Y2CCRuby : public Y2ComponentCreator +{ +private: + Y2Component *cruby; + +public: + /** + * Creates a Ruby component creator + */ + Y2CCRuby() : Y2ComponentCreator( Y2ComponentBroker::BUILTIN ), + cruby (0) {}; + + ~Y2CCRuby () { + if (cruby) + delete cruby; + } + + /** + * Returns true, since the Ruby component is a YaST2 server. + */ + bool isServerCreator() const { return true; }; + + /** + * Creates a new Ruby component. + */ + Y2Component *create( const char * name ) const + { + // create as many as requested, they all share the static YRuby anyway + if ( ! strcmp( name, "ruby") ) return new Y2RubyComponent(); + else return 0; + } + + /** + * always returns the same component, deletes it finally + */ + Y2Component *provideNamespace (const char *name); + +}; + +#endif // ifndef _Y2CCRuby_h + + +// EOF diff --git a/src/ruby/Y2RubyComponent.cc b/src/ruby/Y2RubyComponent.cc new file mode 100644 index 0000000..c6dbcde --- /dev/null +++ b/src/ruby/Y2RubyComponent.cc @@ -0,0 +1,75 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#define y2log_component "Y2Ruby" +#include +#include + +#include "Y2RubyComponent.h" +#include "YRuby.h" +#include "YRubyNamespace.h" +using std::string; + + +Y2RubyComponent::Y2RubyComponent() +{ + // Actual creation of a Ruby interpreter is postponed until one of the + // YRuby static methods is used. They handle that. + + y2milestone( "Creating Y2RubyComponent" ); +} + + +Y2RubyComponent::~Y2RubyComponent() +{ + y2milestone( "Destroying Y2RubyComponent" ); + YRuby::destroy(); +} + + +void Y2RubyComponent::result( const YCPValue & ) +{} + + +Y2Namespace *Y2RubyComponent::import (const char* name) +{ + y2milestone("Creating namespace for import '%s'", name); + // TODO where to look for it + // must be the same in Y2CCRuby and Y2RubyComponent + string module = YCPPathSearch::find (YCPPathSearch::Module, string (name) + ".rb"); + if (module.empty ()) + { + y2internal ("Couldn't find %s after Y2CCRuby pointed to us", name); + return NULL; + } + y2milestone("Found in '%s'", module.c_str()); + module.erase (module.size () - 3 /* strlen (".pm") */); + YCPList args; + args->add (YCPString(/*module*/ name)); + args->add (YCPString(/*module*/ module)); + // load it + YRuby::loadModule (args); + y2milestone("Module '%s' loaded", name); + // introspect, create data structures for the interpreter + Y2Namespace *ns = new YRubyNamespace (name); + + return ns; +} diff --git a/src/ruby/Y2RubyComponent.h b/src/ruby/Y2RubyComponent.h new file mode 100644 index 0000000..a9826ec --- /dev/null +++ b/src/ruby/Y2RubyComponent.h @@ -0,0 +1,76 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#ifndef Y2RubyComponent_h +#define Y2RubyComponent_h + +#include "Y2.h" + + +/** + * @short YaST2 Component: Ruby bindings + */ +class Y2RubyComponent : public Y2Component +{ +public: + /** + * Constructor. + */ + Y2RubyComponent(); + + /** + * Destructor. + */ + ~Y2RubyComponent(); + + /** + * The name of this component. + */ + string name() const { return "ruby"; } + + /** + * Is called by the generic frontend when the session is finished. + */ + void result( const YCPValue & result ); + + /** + * Implements the Ruby:: functions. + **/ +// not yet, prototype the transparent bindings first +// YCPValue evaluate( const YCPValue & val ); + + /** + * Try to import a given namespace. This method is used + * for transparent handling of namespaces (YCP modules) + * through whole YaST. + * @param name_space the name of the required namespace + * @return on errors, NULL should be returned. The + * error reporting must be done by the component itself + * (typically using y2log). On success, the method + * should return a proper instance of the imported namespace + * ready to be used. The returned instance is still owned + * by the component, any other part of YaST will try to + * free it. Thus, it's possible to share the instance. + */ + Y2Namespace *import (const char* name); +}; + +#endif // Y2RubyComponent_h diff --git a/src/ruby/Y2RubyTypeConv.cc b/src/ruby/Y2RubyTypeConv.cc new file mode 100644 index 0000000..5e1c172 --- /dev/null +++ b/src/ruby/Y2RubyTypeConv.cc @@ -0,0 +1,203 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Y2RubyTypePath.h" +#include "Y2RubyTypeTerm.h" + +#include "Y2RubyTypeConv.h" + +#define IS_A(obj,klass) ((rb_obj_is_kind_of((obj),(klass))==Qtrue)?1:0) + +static YCPMap rbhash_2_ycpmap( VALUE value ) +{ + YCPMap map; + VALUE keys = rb_funcall(value, rb_intern("keys"), 0); + int n = NUM2LONG(rb_funcall(keys, rb_intern("size"), 0)); + for ( int i=0; iisVoid()) + { + return Qnil; + } + else if (ycpval->isBoolean()) + { + return ycpval->asBoolean()->value() ? Qtrue : Qfalse; + } + else if (ycpval->isString()) + { + return rb_str_new2(ycpval->asString()->value().c_str()); + } + else if (ycpval->isPath()) + { + // FIXME implement a ruby class for YCPPath + return rb_str_new2(ycpval->asPath()->asString()->value().c_str()); + } + else if (ycpval->isTerm()) + { + return ryast_rterm_from_yterm(ycpval->asTerm()); + } + else if (ycpval->isInteger()) + { + return INT2NUM( ycpval->asInteger()->value() ); + } + else if (ycpval->isFloat()) + { + return rb_float_new(ycpval->asFloat()->value()); + } + else if ( ycpval->isMap() ) + { + VALUE rbhash; + rbhash = rb_hash_new(); + YCPMap map = ycpval->asMap(); + y2internal("map size %d\n", (int) map.size()); + + for ( YCPMapIterator it = map.begin(); it != map.end(); ++it ) + { + YCPValue key = it.key(); + YCPValue value = it.value(); + rb_hash_aset(rbhash, ycpvalue_2_rbvalue(key), ycpvalue_2_rbvalue(value) ); + } + return rbhash; + } + else if (ycpval->isList()) + { + VALUE rblist; + rblist = rb_ary_new(); + YCPList list = ycpval->asList(); + y2internal("list size %d\n",list.size()); + for (int i=0; i < list.size(); i++) + { + rb_ary_push( rblist, ycpvalue_2_rbvalue(list.value(i))); + } + return rblist; + } + else if (ycpval->isSymbol()) + { + YCPSymbol symbol = ycpval->asSymbol(); + return rb_intern(symbol->symbol_cstr()); + } + rb_raise( rb_eTypeError, "Conversion of YCP type %s not supported", ycpval->toString().c_str() ); + return Qnil; +} + +// isEmpty size add remove (value n) toString +YCPValue +rbvalue_2_ycpvalue( VALUE value ) +{ + VALUE klass = rb_funcall( value, rb_intern("class"), 0); + //std::cout << RSTRING( rb_funcall( klass, rb_intern("to_s"), 0))->ptr << " | " << RSTRING(rb_funcall( value, rb_intern("inspect"), 0))->ptr << std::endl; + //y2internal("type: '%d'", TYPE(value)); + // TODO conver integers, and add support for lists, ah, and boleans! + switch (TYPE(value)) + { + case T_NIL: + return YCPVoid(); + case T_STRING: + return YCPString(RSTRING (value)->ptr); + break; + case T_TRUE: + return YCPBoolean(true); + break; + case T_FALSE: + return YCPBoolean(false); + break; + case T_FIXNUM: + return YCPInteger(NUM2LONG(value)); + break; + case T_FLOAT: + return YCPFloat(NUM2DBL(value)); + break; + case T_ARRAY: + return rbarray_2_ycplist(value); + break; + case T_HASH: + return rbhash_2_ycpmap(value); + break; + case T_SYMBOL: + return YCPSymbol(rb_id2name(rb_to_id(value))); + //case T_DATA: + // rb_raise( rb_eRuntimeError, "Object"); + break; + default: + string class_name(RSTRING(rb_funcall(rb_funcall(value, rb_intern("class"), 0), rb_intern("to_s"), 0))->ptr); + /* get the Term class object */ + if ( class_name == "YaST::Term" ) + { + return ryast_yterm_from_rterm(value); + } + rb_raise( rb_eTypeError, "Conversion of Ruby type not supported"); + return YCPValue(); + } +} + +YCPValue +rbvalue_2_ycppath( VALUE value ) +{ + VALUE stringrep = rb_funcall(value, rb_intern("to_s"), 0); + return YCPPath(RSTRING(stringrep)->ptr); +} + diff --git a/src/ruby/Y2RubyTypeConv.h b/src/ruby/Y2RubyTypeConv.h new file mode 100644 index 0000000..d440d98 --- /dev/null +++ b/src/ruby/Y2RubyTypeConv.h @@ -0,0 +1,50 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#ifndef Y2RUBYTYPECONV_H +#define Y2RUBYTYPECONV_H + +#include +#include "ruby.h" + +/** + * Converts a YCPValue into a Ruby Value + * Supports neested lists and maps using recursion. + */ +extern "C" VALUE +ycpvalue_2_rbvalue( YCPValue ycpval ); + +/** + * Converts a Ruby Value into a YCPValue + * Supports neested lists and maps using recursion. + */ +YCPValue +rbvalue_2_ycpvalue( VALUE value ); + + +/** + * excplicitly create a YCPPath from a Ruby value + */ +YCPValue +rbvalue_2_ycppath( VALUE value ); + +#endif + diff --git a/src/ruby/Y2RubyTypePath.cc b/src/ruby/Y2RubyTypePath.cc new file mode 100644 index 0000000..78bfad1 --- /dev/null +++ b/src/ruby/Y2RubyTypePath.cc @@ -0,0 +1,75 @@ +#include "YRuby.h" +#include "Y2RubyTypePath.h" +#include + +static VALUE ryast_cPath; + +struct ryast_Path_Wrapper +{ + YCPPath path; +}; + +//----------------------------------------------------------------------------- +// internal used only + +static void +ryast_path_set_path( VALUE self, const YCPPath & path ) +{ + ryast_Path_Wrapper *wrapper; + Data_Get_Struct(self, ryast_Path_Wrapper, wrapper); + wrapper->path = path; +} + +static void +ryast_path_mark (ryast_Path_Wrapper *r) +{ + +} + +static void +ryast_path_free (ryast_Path_Wrapper *r) +{ + delete r; +} + +static VALUE +ryast_path_initialize( int argc, VALUE *argv, VALUE self ) +{ + ryast_Path_Wrapper *wrapper; + Data_Get_Struct(self, ryast_Path_Wrapper, wrapper); + + // we should be using rb_scan_args here but I couldn't get it to work. + +// if (argc > 0) { +// Check_Type( argv[0], T_STRING); +// version = StringValuePtr( argv[0] ); +// } +// if (argc > 1) { +// Check_Type( argv[1], T_STRING); +// release = StringValuePtr( argv[1] ); +// } +// if (argc > 2) { +// Check_Type( argv[2], T_FIXNUM); +// epoch = FIX2INT( argv[2] ); +// } + wrapper->path = YCPPath(); + return self; +} + + +static VALUE +ryast_path_allocate(VALUE klass) +{ + // create struct + ryast_Path_Wrapper *wrapper = new ryast_Path_Wrapper(); + // wrap and return struct + return Data_Wrap_Struct (klass, ryast_path_mark, ryast_path_free, wrapper); +} + +void +ryast_path_init( VALUE super ) +{ + ryast_cPath = rb_define_class_under( super, "Path", rb_cObject ); + rb_define_alloc_func( ryast_cPath, ryast_path_allocate ); + rb_define_method( ryast_cPath, "initialize", RB_METHOD( ryast_path_initialize ), -1 ); +} diff --git a/src/ruby/Y2RubyTypePath.h b/src/ruby/Y2RubyTypePath.h new file mode 100644 index 0000000..5e33aaf --- /dev/null +++ b/src/ruby/Y2RubyTypePath.h @@ -0,0 +1,30 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#ifndef Y2RUBY_TYPE_PATH_H +#define Y2RUBY_TYPE_PATH_H + +#include + +void ryast_path_init( VALUE super ); + +#endif + diff --git a/src/ruby/Y2RubyTypeTerm.cc b/src/ruby/Y2RubyTypeTerm.cc new file mode 100644 index 0000000..8518d07 --- /dev/null +++ b/src/ruby/Y2RubyTypeTerm.cc @@ -0,0 +1,171 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#include "YRuby.h" +#include "Y2RubyTypeConv.h" +#include "Y2RubyTypeTerm.h" +#include + +static VALUE ryast_cTerm; + +struct ryast_Term_Wrapper +{ + ryast_Term_Wrapper() + : term("init-me") + { + + } + YCPTerm term; +}; + +//----------------------------------------------------------------------------- +// internal used only + +static void +ryast_term_set_term( VALUE self, const YCPTerm & term ) +{ + ryast_Term_Wrapper *wrapper; + Data_Get_Struct(self, ryast_Term_Wrapper, wrapper); + wrapper->term = term; +} + +VALUE +ryast_rterm_from_yterm( const YCPTerm &term ) +{ + VALUE rterm_obj = rb_funcall( ryast_cTerm, rb_intern("new"), 0); + ryast_term_set_term( rterm_obj, term ); + return rterm_obj; +} + +YCPTerm +ryast_yterm_from_rterm( VALUE term ) +{ + ryast_Term_Wrapper *wrapper; + Data_Get_Struct(term, ryast_Term_Wrapper, wrapper); + return wrapper->term; +} + +static void +ryast_term_mark (ryast_Term_Wrapper *r) +{ + +} + +static void +ryast_term_free (ryast_Term_Wrapper *r) +{ + delete r; +} + +static VALUE +ryast_term_initialize( int argc, VALUE *argv, VALUE self ) +{ + ryast_Term_Wrapper *wrapper; + Data_Get_Struct(self, ryast_Term_Wrapper, wrapper); + + // we should be using rb_scan_args here but I couldn't get it to work. + + // we need at least the name to create a YCPTerm + Check_Type( argv[0], T_STRING); + wrapper->term = YCPTerm( RSTRING(argv[0])->ptr ); + // add the remaining YCPTerm arguments + if (argc > 1) + { + int i=1; + for ( ; iterm->add(rbvalue_2_ycpvalue(argv[i])); + } + } + return self; +} + +static VALUE +ryast_term_add( int argc, VALUE *argv, VALUE self ) +{ + ryast_Term_Wrapper *wrapper; + Data_Get_Struct(self, ryast_Term_Wrapper, wrapper); + + // we should be using rb_scan_args here but I couldn't get it to work. + + // add the remaining YCPTerm arguments + if (argc > 0) + { + int i=0; + for ( ; iterm->add(value); + } + } + return self; +} + +static VALUE +ryast_term_allocate(VALUE klass) +{ + // create struct + ryast_Term_Wrapper *wrapper = new ryast_Term_Wrapper(); + // wrap and return struct + return Data_Wrap_Struct (klass, ryast_term_mark, ryast_term_free, wrapper); +} + + +static VALUE +ryast_term_to_s(VALUE self) +{ + ryast_Term_Wrapper *wrapper; + Data_Get_Struct(self, ryast_Term_Wrapper, wrapper); + return rb_str_new2(wrapper->term.toString().c_str()); +} + +static VALUE +ryast_term_name(VALUE self) +{ + ryast_Term_Wrapper *wrapper; + Data_Get_Struct(self, ryast_Term_Wrapper, wrapper); + return rb_str_new2(wrapper->term.name().c_str()); +} + +// static VALUE +// ryast_term_set_name(VALUE self, VALUE name) +// { +// Check_Type(name, T_STRING); +// ryast_Term_Wrapper *wrapper; +// Data_Get_Struct(self, ryast_Term_Wrapper, wrapper); +// +// wrapper->term->setName(RSTRING(name)->ptr); +// return self; +// } + +void +ryast_term_init( VALUE super ) +{ + //std::cout << "Hi! term" << std::endl; + ryast_cTerm = rb_define_class_under( super, "Term", rb_cObject ); + rb_define_alloc_func( ryast_cTerm, ryast_term_allocate ); + rb_define_method( ryast_cTerm, "initialize", RB_METHOD( ryast_term_initialize ), -1 ); + rb_define_method( ryast_cTerm, "add", RB_METHOD( ryast_term_add ), -1 ); + //rb_define_method( ryast_cTerm, "name=", RB_METHOD( ryast_term_set_name ), 1 ); + rb_define_method( ryast_cTerm, "name", RB_METHOD( ryast_term_name ), 0 ); + rb_define_method( ryast_cTerm, "to_s", RB_METHOD( ryast_term_to_s ), 0 ); +} diff --git a/src/ruby/Y2RubyTypeTerm.h b/src/ruby/Y2RubyTypeTerm.h new file mode 100644 index 0000000..ecf54c4 --- /dev/null +++ b/src/ruby/Y2RubyTypeTerm.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#ifndef Y2RUBY_TYPE_TERM_H +#define Y2RUBY_TYPE_TERM_H + +#include + +void ryast_term_init( VALUE super ); + +VALUE +ryast_rterm_from_yterm( const YCPTerm &term ); + +YCPTerm +ryast_yterm_from_rterm( VALUE term ); + +#endif + diff --git a/src/ruby/YCP.cc b/src/ruby/YCP.cc new file mode 100644 index 0000000..a2188df --- /dev/null +++ b/src/ruby/YCP.cc @@ -0,0 +1,473 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +// #include +// #include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ruby.h" + +//#include "YRuby.h" +#include "RubyLogger.h" +#include "Y2RubyTypePath.h" +#include "Y2RubyTypeTerm.h" +#include "Y2RubyTypeConv.h" +#include "YRuby.h" + +static VALUE rb_mYaST; +static VALUE rb_mUi; +static VALUE rb_cBroker; + +// make the compiler happy when +// calling rb_define_method() +typedef VALUE (ruby_method)(...); + +// more useful macros +#define RB_FINALIZER(func) ((void (*)(...))func) + +// this macro saves us from typing +// (ruby_method*) & method_name +// in rb_define_method +#define RB_METHOD(func) ((VALUE (*)(...))func) + +Y2Component *owned_uic = 0; +Y2Component *owned_wfmc = 0; + +static +Y2Namespace * +getNs (const char * ns_name, const char * func_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); + } + else + { + ns->initialize (); + } + return ns; +} + +void init_wfm() +{ + y2milestone("init_wfm"); +// if (Y2WFMComponent::instance () == 0) +// { + y2milestone("WFM init"); + owned_wfmc = Y2ComponentBroker::createClient ("wfm"); + if (owned_wfmc == 0) + { + y2error ("Cannot create WFM component"); + } +// } +} + +static VALUE +rb_init_ui( int argc, VALUE *argv, VALUE self ) +{ + const char *ui_name = "ncurses"; + + if (argc == 1) + { + Check_Type(argv[0], T_STRING); + ui_name = RSTRING(argv[0])->ptr; + } + else if (argc != 0) + { + y2error ("Zero or one arguments required (ui name, default %s", ui_name); + return Qnil; + } + + Y2Component *c = YUIComponent::uiComponent (); + if (c == 0) + { + y2debug ("UI component not created yet, creating %s", ui_name); + + c = Y2ComponentBroker::createServer (ui_name); + if (c == 0) + { + y2error ("Cannot create component %s", ui_name); + return Qnil; + } + + if (YUIComponent::uiComponent () == 0) + { + y2error ("Component %s is not a UI", ui_name); + return Qnil; + } + else + { + // got it - initialize, remember + c->setServerOptions (0, NULL); + owned_uic = c; + } + } + else + { + y2debug ("UI component already present: %s", c->name ().c_str ()); + } + 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 ); + +VALUE +yast_module_proxy_method( int argc, VALUE *argv, VALUE self ) +{ + VALUE symbol = argv[0]; + VALUE namespace_name = rb_iv_get(self, "@namespace_name"); + + // 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("Dynamic Proxy: [%s::%s] with [%d] params\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc); + + //Check_Type(argv[0], T_STRING); + //y2internal(RSTRING (symbol)->ptr); + //Data_Get_Struct( self, class Y2Namespace, ns ); + //ns = gNameSpaces[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; + } + + 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()); + + // import the namespace + //Y2Namespace *ns = c->import(RSTRING (namespace_name)->ptr); + Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr); + if (ns == NULL) + { + rb_raise( rb_eRuntimeError, "Component cannot import namespace %s", RSTRING (namespace_name)->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); + + if (sym_te == NULL) + { + y2error ("No such symbol %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr); + rb_raise( rb_eNameError, "YCP symbol '%s' not found in namespace '%s'", RSTRING(symbol_str)->ptr, RSTRING (namespace_name)->ptr ); + return Qnil; + } + + if (sym_te->sentry ()->isVariable () || + sym_te->sentry ()->isReference ()) + { + // set the variable + //ret_yv = YCP_getset_variable (aTHX_ ns_name, sym_te->sentry (), args); + } + else + { // no indent yet + Y2Function* call = ns->createFunctionCall (RSTRING(symbol_str)->ptr, 0 /*Type::fromSignature("list()")*/); + + if (call == NULL) + { + y2internal ("Cannot create function call %s\n", RSTRING(symbol_str)->ptr); + return 4; + } + + // add the parameters + for (int i=1; itoString()); + call->appendParameter (v); + } + call->finishParameters (); + + YCPValue res = call->evaluateCall (); + delete call; + 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 ) +{ + // 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 (); + } + + 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); + return YCPNull (); + } + y2milestone("builtin '%s' found.", module_name.c_str()); + // construct a builtin call using the proper overloaded builtin + YEBuiltin *bi_call = new YEBuiltin (bi_dt); + + // attach the parameters: + + // 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) + { + 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 ) + 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. + // Can't know parameter name? + y2error ("... when passing parameter #%u to builtin %s", + j, qualified_name); + return YCPNull (); + } + // Such YConsts without a specific type produce invalid + // bytecode. (Which is OK here) + // The actual parameter's YCode becomes owned by the function call? + YConst *param_c = new YConst (YCode::ycConstant, param_v); + // for attaching the parameter, must get the real type so that it matches + constTypePtr act_param_tp = Type::vt2type (param_v->valuetype ()); + // Attach the parameter + // Returns NULL if OK, Type::Error if excessive argument + // Other errors (bad code, bad type) shouldn't happen + constTypePtr err_tp = bi_call->attachParameter (param_c, act_param_tp); + if (err_tp != NULL) + { + if (err_tp->isError ()) + { + // TODO really need to know the place in Ruby code + // where we were called from. + y2error ("Excessive parameter to builtin %s", qualified_name); + } + else + { + y2internal ("attachParameter returned %s", err_tp->toString ().c_str ()); + } + return YCPNull (); + } + } // for each actual parameter + + // now must check if we got fewer parameters than needed + // or there was another error while resolving the overload + constTypePtr err_tp = bi_call->finalize (RubyLogger::instance ()); + if (err_tp != NULL) + { + // apparently the error was already reported? + y2error ("Error type %s when finalizing builtin %s", + err_tp->toString ().c_str (), qualified_name); + return YCPNull (); + } + + // go call it now! + y2debug ("Ruby is calling builtin %s", qualified_name); + YCPValue ret_yv = bi_call->evaluate (false /* no const subexpr elim */); + delete bi_call; + + return ret_yv; +} + + + +//y2_logger_helper + +//y2_logger (level, comp, file, line, function, "%s", message); + +static VALUE +rb_y2_logger( int argc, VALUE *argv, VALUE self ) +{ + Check_Type(argv[0], T_FIXNUM); + Check_Type(argv[1], T_STRING); + Check_Type(argv[2], T_STRING); + Check_Type(argv[3], T_FIXNUM); + Check_Type(argv[4], T_STRING); + + int i; + for ( i = 5; i < argc; i++) + { + Check_Type(argv[i], T_STRING); + } + y2_logger((loglevel_t)NUM2INT(argv[0]),RSTRING(argv[1])->ptr,RSTRING(argv[2])->ptr,NUM2INT(argv[3]),"",RSTRING(argv[5])->ptr); + return Qnil; +} + +extern "C" +{ + void + Init_yastx() + { + YCPPathSearch::initialize (); + + for ( list::const_iterator it = YCPPathSearch::searchListBegin (YCPPathSearch::Module); it != YCPPathSearch::searchListEnd (YCPPathSearch::Module) ; ++it ) + { + y2internal("%s\n", (*it).c_str() ); + } + + rb_mYaST = rb_define_module("YaST"); + rb_mUi = rb_define_module_under(rb_mYaST, "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, "name", RB_METHOD(yast_module_name), -1); + + ryast_path_init(rb_mYaST); + ryast_term_init(rb_mYaST); + } +} diff --git a/src/ruby/YCP.rb b/src/ruby/YCP.rb new file mode 100644 index 0000000..fb820b5 --- /dev/null +++ b/src/ruby/YCP.rb @@ -0,0 +1,520 @@ +#! /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/YRuby.cc b/src/ruby/YRuby.cc new file mode 100644 index 0000000..07ab59a --- /dev/null +++ b/src/ruby/YRuby.cc @@ -0,0 +1,173 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#include +#include +#include +#include +#include + +// Ruby stuff +#include + + +#define y2log_component "Y2Ruby" +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "YRuby.h" + +#define DIM(ARRAY) ( sizeof( ARRAY )/sizeof( ARRAY[0] ) ) + +#include "Y2RubyTypeConv.h" + +static void prependModulePath() +{ + YCPPathSearch::initialize (); + + list::const_iterator + b = YCPPathSearch::searchListBegin (YCPPathSearch::Module), + e = YCPPathSearch::searchListEnd (YCPPathSearch::Module), + i; + + // count the number of directories to prepend +// int n = 0; +// for (i = b; i != e; ++i) +// { +// // do something +// } +} + +YRuby * YRuby::_yRuby = 0; + +YRuby::YRuby() +{ + y2milestone( "Initializing ruby interpreter." ); + ruby_init(); + //ruby_options(argc - 1, ++argv); + ruby_script("yast"); + ruby_init_loadpath(); +} + +YRuby::~YRuby() +{ + y2milestone( "Shutting down ruby interpreter." ); + ruby_finalize(); +} + + +YRuby * +YRuby::yRuby() +{ + if ( ! _yRuby ) + _yRuby = new YRuby(); + + return _yRuby; +} + + +YCPValue +YRuby::destroy() +{ + if ( _yRuby ) + delete _yRuby; + + _yRuby = 0; + + return YCPVoid(); +} + +/** + * Loads a module. + */ +YCPValue +YRuby::loadModule( YCPList argList ) +{ + YRuby::yRuby(); + //y2milestone("loadModule 1"); + if ( argList->size() != 2 || ! argList->value(0)->isString() || ! argList->value(1)->isString() ) + return YCPError( "Ruby::loadModule() / Ruby::Use() : Bad arguments: String expected!" ); + //y2milestone("loadModule 2"); + string module_name = argList->value(0)->asString()->value(); + string module_path = argList->value(1)->asString()->value(); + //y2milestone("loadModule 3: '%s'", module_name.c_str()); + string require_module = "require(\"" + module_path + "\")"; + //y2milestone("loadModule 3.5"); + VALUE result = rb_eval_string((require_module).c_str()); + if ( result == Qfalse ) + return YCPError( "Ruby::loadModule() / Can't load ruby module '" + module_path + "'" ); + //y2milestone("loadModule 4"); + return YCPVoid(); +} + + + +/** + * @param argList arguments start 1!, 0 is dummy + */ +YCPValue +YRuby::callInner (string module_name, string function, bool method, + YCPList argList, constTypePtr wanted_result_type) +{ + VALUE module = rb_funcall( rb_mKernel, rb_intern("const_get"), 1, rb_str_new2(module_name.c_str()) ); + if (module == Qnil) + { + y2error ("The Ruby module '%s' is not provided by its rb file", module_name.c_str()); + return YCPVoid(); + } + + // first element of the list is ignored + int size = argList.size(); + + // make rooms for size-1 arguments to + // the ruby function + VALUE values[size-1]; + int i=0; + for ( ; i < size-1; ++i ) + { + // get the + YCPValue v = argList->value(i+1); + y2milestone("Adding argument %d of type %s", i, v->valuetype_str()); + values[i] = ycpvalue_2_rbvalue(v); + } + + y2milestone( "Wll call function '%s' in module '%s' with '%d' arguments", function.c_str(), module_name.c_str(), size-1); + VALUE result = rb_funcall2( module, rb_intern(function.c_str()), size-1, values ); + //VALUE result = rb_funcall( module, rb_intern(function.c_str()), 2, INT2NUM(2), INT2NUM(3) ); + y2milestone( "Called function '%s' in module '%s'", function.c_str(), module_name.c_str()); + return rbvalue_2_ycpvalue(result); +} + diff --git a/src/ruby/YRuby.h b/src/ruby/YRuby.h new file mode 100644 index 0000000..89dd7b1 --- /dev/null +++ b/src/ruby/YRuby.h @@ -0,0 +1,107 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#ifndef YRuby_h +#define YRuby_h + +// Ruby stuff +#include + +#include +#include + +// make the compiler happy when +// calling rb_define_method() +typedef VALUE (ruby_method)(...); + +// more useful macros +#define RB_FINALIZER(func) ((void (*)(...))func) + +// this macro saves us from typing +// (ruby_method*) & method_name +// in rb_define_method +#define RB_METHOD(func) ((VALUE (*)(...))func) + +class YRuby +{ +public: + + /** + * Load a Ruby module - equivalent to "use" in Ruby. + * + * Returns a YCPError on failure, YCPVoid on success. + **/ + static YCPValue loadModule( YCPList argList ); + + /** + * Access the static (singleton) YRuby object. Create it if it isn't + * created yet. + * + * Returns 0 on error. + **/ + static YRuby * yRuby(); + + /** + * Destroy the static (singleton) YRuby object and unload the embedded Ruby + * interpreter. + * + * Returns YCPVoid(). + **/ + static YCPValue destroy(); + + +protected: + + /** + * Protected constructor. Use one of the static methods rather than + * instantiate an object of this class yourself. + **/ + YRuby(); + + /** + * Protected constructor. Use one of the static methods rather than + * instantiate an object of this class yourself. + **/ + + /** + * Destructor. + **/ + ~YRuby(); + + /** + * Returns the internal embedded Ruby interpreter. + **/ + + +public: + /** + * Generic Ruby call. + **/ + YCPValue callInner (string module, string function, bool method, + YCPList argList, constTypePtr wanted_result_type); + +protected: + +public: + static YRuby * _yRuby; +}; + +#endif // YRuby_h diff --git a/src/ruby/YRubyNamespace.cc b/src/ruby/YRubyNamespace.cc new file mode 100644 index 0000000..b338745 --- /dev/null +++ b/src/ruby/YRubyNamespace.cc @@ -0,0 +1,314 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#include "YRubyNamespace.h" + +// Ruby stuff +#include + +#define y2log_component "Y2Ruby" +#include + +#include +#include +#include +//#include +#include "YRuby.h" +#include + +/** + * using this instead of plain strcmp + * enables embedding argument names into the typeinfo + */ +static bool firstWordIs (const char *where, const char *what) +{ + size_t n = strlen (what); + return !strncmp (where, what, n) && + (where[n] == '\0' || isspace (where[n])); +} + +/** + * The definition of a function that is implemented in Ruby + */ +class Y2RubyFunctionCall : public Y2Function +{ + //! module name + string m_module_name; + //! function name, excluding module name + string m_local_name; + //! function type + constFunctionTypePtr m_type; + //! data prepared for the inner call + YCPList m_call; + +public: + Y2RubyFunctionCall (const string &module_name, + const string &local_name, + constFunctionTypePtr function_type + ) : + m_module_name (module_name), + m_local_name (local_name), + m_type (function_type) + { + // placeholder, formerly function name + m_call->add (YCPVoid ()); + } + + //! if true, the ruby function is passed the module name + virtual bool isMethod () = 0; + + //! called by YEFunction::evaluate + virtual YCPValue evaluateCall () + { + return YRuby::yRuby()->callInner ( m_module_name, + m_local_name, + isMethod (), + m_call, + m_type->returnType() ); + } + /** + * Attaches a parameter to a given position to the call. + * @return false if there was a type mismatch + */ + virtual bool attachParameter (const YCPValue& arg, const int position) + { + m_call->set (position+1, arg); + return true; + } + + /** + * What type is expected for the next appendParameter (val) ? + * (Used when calling from Ruby, to be able to convert from the + * simple type system of Ruby to the elaborate type system of YCP) + * @return Type::Any if number of parameters exceeded + */ + virtual constTypePtr wantedParameterType () const + { + // -1 for the function name + int params_so_far = m_call->size ()-1; + return m_type->parameterType (params_so_far); + } + + /** + * Appends a parameter to the call. + * @return false if there was a type mismatch + */ + virtual bool appendParameter (const YCPValue& arg) + { + y2internal("Adding parameter to function %s::%s of type %s", m_module_name.c_str(), m_local_name.c_str(), arg->valuetype_str()); + m_call->add (arg); + return true; + } + + /** + * Signal that we're done adding parameters. + * @return false if there was a parameter missing + */ + virtual bool finishParameters () + { + return true; + } + + + virtual bool reset () + { + m_call = YCPList (); + // placeholder, formerly function name + m_call->add (YCPVoid ()); + return true; + } + + /** + * Something for remote namespaces + */ + virtual string name () const + { + return m_local_name; + } +}; + +class Y2RubySubCall : public Y2RubyFunctionCall +{ +public: + Y2RubySubCall (const string &module_name, + const string &local_name, + constFunctionTypePtr function_type + ) : + Y2RubyFunctionCall (module_name, local_name, function_type) + {} + virtual bool isMethod () + { + return false; + } +}; + +class Y2RubyMethodCall : public Y2RubyFunctionCall +{ +public: + Y2RubyMethodCall (const string &module_name, + const string &local_name, + constFunctionTypePtr function_type + ) : + Y2RubyFunctionCall (module_name, local_name, function_type) + {} + virtual bool isMethod () + { + return true; + } +}; + + + +YRubyNamespace::YRubyNamespace (string name) + : m_name (name), + m_all_methods (true) +{ + y2milestone("Creating namespace for '%s'", name.c_str()); + + //y2milestone("loadModule 3.5"); + //VALUE result = rb_eval_string((require_module).c_str()); + + VALUE module = rb_funcall( rb_mKernel, rb_intern("const_get"), 1, rb_str_new2(name.c_str()) ); + if (module == Qnil) + { + y2error ("The Ruby module '%s' is not provided by its rb file", name.c_str()); + return; + } + y2milestone("The module '%s' was found", name.c_str()); + + // we will perform operator- to determine the module methods + VALUE moduleklassmethods = rb_funcall( rb_cModule, rb_intern("methods"), 0); + VALUE mymodulemethods = rb_funcall( module, rb_intern("methods"), 0); + VALUE methods = rb_funcall( mymodulemethods, rb_intern("-"), 1, moduleklassmethods ); + + if (methods == Qnil) + { + y2error ("Can't see methods in module '%s'", name.c_str()); + return; + } + + int i; + for(i = 0; i < RARRAY(methods)->len; i++) + { + VALUE current = RARRAY(methods)->ptr[i]; + y2milestone("New method: '%s'", RSTRING(current)->ptr); + + constTypePtr sym_tp = Type::Unspec; + //sym_tp = parseTypeinfo (*sym_ti) + if (sym_tp->isError ()) + { + y2error ("Cannot parse $TYPEINFO{%s}", RSTRING(current)->ptr); + continue; + } + if (sym_tp->isUnspec ()) + { + //sym_tp = new FunctionType (Type::Any, new FunctionType(Type::Any) ); + // figure out arity. + y2milestone("1."); + Check_Type(module,T_MODULE); + VALUE methodobj = rb_funcall( module, rb_intern("method"), 1, current ); + //VALUE methodobj = rb_funcall( module, rb_intern("send"), 2, rb_str_new2("method"), current ); + if ( methodobj == Qnil ) + { + y2error ("Cannot access method object '%s'", RSTRING(current)->ptr); + continue; + } + y2milestone("2."); + string signature = "any( "; + VALUE rbarity = rb_funcall( methodobj, rb_intern("arity"), 0); + y2milestone("3."); + int arity = NUM2INT(rbarity); + for ( int k=0; k < arity; ++k ) + { + signature += "any"; + if ( k < (arity - 1) ) + signature += ","; + } + signature += ")"; + y2internal("going to parse signature: '%s'", signature.c_str()); + sym_tp = Type::fromSignature(signature); + } + + constFunctionTypePtr fun_tp = (constFunctionTypePtr) sym_tp; + + // symbol entry for the function + SymbolEntry *fun_se = new SymbolEntry ( this, + i,// position. arbitrary numbering. must stay consistent when? + RSTRING(current)->ptr, // passed to Ustring, no need to strdup + SymbolEntry::c_function, + sym_tp); + fun_se->setGlobal (true); + // enter it to the symbol table + enterSymbol (fun_se, 0); + y2milestone("method: '%s' added", RSTRING(current)->ptr); + y2milestone("%s", symbolsToString().c_str()); + } +} + +YRubyNamespace::~YRubyNamespace () +{} + +const string YRubyNamespace::filename () const +{ + // TODO improve + return ".../" + m_name; +} + +// this is for error reporting only? +string YRubyNamespace::toString () const +{ + y2error ("TODO"); + return "{\n" + "/* this namespace is provided in Ruby */\n" + "}\n"; +} + +// called when running and the import statement is encountered +// does initialization of variables +// constructor is handled separately after this +YCPValue YRubyNamespace::evaluate (bool cse) +{ + // so we don't need to do anything + y2debug ("Doing nothing"); + return YCPNull (); +} + +// It seems that this is the standard implementation. why would we +// ever want it to be different? +Y2Function* YRubyNamespace::createFunctionCall (const string name, constFunctionTypePtr required_type) +{ + y2debug ("Creating function call for %s", name.c_str ()); + TableEntry *func_te = table ()->find (name.c_str (), SymbolEntry::c_function); + if (func_te) + { + constTypePtr t = required_type ? required_type : (constFunctionTypePtr)func_te->sentry()->type (); + if (m_all_methods) + { + return new Y2RubyMethodCall (m_name, name, t); + } + else + { + return new Y2RubySubCall (m_name, name, t); + } + } + y2error ("No such function %s", name.c_str ()); + return NULL; +} diff --git a/src/ruby/YRubyNamespace.h b/src/ruby/YRubyNamespace.h new file mode 100644 index 0000000..0b8eb92 --- /dev/null +++ b/src/ruby/YRubyNamespace.h @@ -0,0 +1,58 @@ +/*---------------------------------------------------------------------\ +| | +| __ __ ____ _____ ____ | +| \ \ / /_ _/ ___|_ _|___ \ | +| \ 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. + +*/ + +#include +#include +#include +#include + +/** + * YaST interface to a Ruby module + */ +class YRubyNamespace : public Y2Namespace +{ +private: + string m_name; //! this namespace's name, eg. XML::Writer + bool m_all_methods; //! add the class name to all calls +public: + /** + * Construct an interface. The module must be already loaded + * @param name eg "XML::Writer" + */ + YRubyNamespace (string name); + + virtual ~YRubyNamespace (); + + //! what namespace do we implement + virtual const string name () const { return m_name; } + //! used for error reporting + virtual const string filename () const; + + //! unparse. useful only for YCP namespaces?? + virtual string toString () const; + //! called when evaluating the import statement + // constructor is handled separately + virtual YCPValue evaluate (bool cse = false); + + virtual Y2Function* createFunctionCall (const string name, constFunctionTypePtr requiredType); +private: + VALUE _module_instance; +}; diff --git a/src/ruby/YaPI.pm.in b/src/ruby/YaPI.pm.in new file mode 100644 index 0000000..c991d30 --- /dev/null +++ b/src/ruby/YaPI.pm.in @@ -0,0 +1,246 @@ +# -*- 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 new file mode 100644 index 0000000..e205cc0 --- /dev/null +++ b/src/ruby/yast.rb @@ -0,0 +1,141 @@ +# -----------------------------------------------------------------------\ +# | | +# | __ __ ____ _____ ____ | +# | \ \ / /_ _/ ___|_ _|___ \ | +# | \ 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 'yastx' + +module YaST + module Ui + #my @e_logging = qw(y2debug y2milestone y2warning y2error y2security y2internal); + + # Define symbols for the UI + ui_terms = [ :BarGraph, :Bottom, :CheckBox, :ColoredLabel, :ComboBox, :Date, + :DownloadProgress, :DumbTab, :DummySpecialWidget, :Empty, :Frame, :HBox, :HBoxvHCenter, + :HMultiProgressMeter, :HSpacing, :HSquash, :HStretch, :HVCenter, :HVSquash, + :HVStretch, :HWeight, :Heading, :IconButton, :Image, :IntField, :Label, :Left, :LogView, + :MarginBox, :MenuButton, :MinHeight, :MinSize, :MinWidth, :MultiLineEdit, + :MultiSelectionBox, :PackageSelector, :PatternSelector, :PartitionSplitter, + :Password, :PkgSpecial, :ProgressBar, :PushButton, :RadioButton, + :RadioButtonGroup, :ReplacePoint, :RichText, :Right, :SelectionBox, :Slider, :Table, + :TextEntry, :Time, :Top, :Tree, :VBox, :VCenter, :VMultiProgressMeter, :VSpacing, + :VSquash, :VStretch, :VWeight, :Wizard, + :id, :opt ] + +# buffer = String.new +# buffer << "[" +# ui_terms.each do |t| +# buffer << " :" << t.to_s.downcase << "," +# end +# buffer << " ]" +# puts buffer + # If the method name contains underscores, convert to camel case +# while method =~ /([^_]*)_(.)(.*)/ +# method = $1 + $2.upcase + $3 +# end + + # for each symbol define a util function that will create a term + ui_terms.each do | term_name | + define_method(term_name) do | *args | + t = YaST::Term.new(term_name.to_s) + args.each do |arg| + t.add(arg) + end + return t + end + alias_method term_name.to_s.downcase, term_name + end + + end # end Ui module +end + +module YaST + + class TermBuilder + # blank slate + instance_methods.each { |m| undef_method m unless (m =~ /^__|instance_eval$/)} + + def initialize(&block) + @term = nil + @term = instance_eval(&block) + end + + def method_missing(name, *args, &block ) + # puts "hi #{name.to_s} | #{args}" + term = nil + elements = block ? nil : args + @__to_s = nil # invalidate to_s cache + term = YaST::Term.new(name.to_s) + if not elements.nil? + elements.each do | e | + term.add(e) + end + return term + else + r = instance_eval(&block) + puts term.class + term.add(r) if not r.nil? + end + return term + end + + def to_s + return @term.to_s + end + + def term + return @term + 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 diff --git a/src/swig/CMakeLists.txt b/src/swig/CMakeLists.txt new file mode 100644 index 0000000..2ecda54 --- /dev/null +++ b/src/swig/CMakeLists.txt @@ -0,0 +1,30 @@ + +SET( SWIG_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/yast_wrap.cxx" ) +SET( SWIG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/yast.i" ) + +ADD_CUSTOM_COMMAND ( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/yast_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 ${CMAKE_COMMAND} -E echo "Done." + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/yast.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 ) + +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} ) + +INSTALL(TARGETS ryast LIBRARY DESTINATION ${RUBY_ARCH_DIR} ) \ No newline at end of file diff --git a/src/swig/yast.i b/src/swig/yast.i new file mode 100644 index 0000000..5562714 --- /dev/null +++ b/src/swig/yast.i @@ -0,0 +1,218 @@ +%module ryast +%include std_string.i +%include stl.i + %{ +/* Includes the header in the wrapper code */ +#include +#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" +#endif + +%rename("+") "operator+"; +%rename("<<") "operator<<"; +%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" diff --git a/yast2-ruby-bindings.spec.in b/yast2-ruby-bindings.spec.in new file mode 100644 index 0000000..b481aae --- /dev/null +++ b/yast2-ruby-bindings.spec.in @@ -0,0 +1,57 @@ + + +# +# spec file for package yast2-ruby-bindings (Version 0.1) +# +# norootforbuild + +Name: yast2-ruby-bindings +Version: @VERSION@ +Release: 0 +License: GPL +Group: System/YaST +BuildRoot: %{_tmppath}/%{name}-%{version}-build +Source0: yast2-ruby-bindings-%{version}.tar.bz2 +prefix: /usr + +BuildRequires: swig cmake gcc-c++ libxcrypt-devel yast2-core-devel yast2-devtools +# libzypp-devel is missing .la requires +BuildRequires: ruby-devel +Requires: yast2-core >= 2.13.28 +Requires: ruby +Summary: Ruby bindings for the YaST platform. + +%description +The bindings allow YaST modules to be written using the Ruby language and also +Ruby scripts can use YaST agents, APIs and modules. + +Author + +%prep +%setup -n yast2-ruby-bindings-%{version} +%build +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX=%{prefix} \ + -DLIB=%{_lib} \ + -DCMAKE_C_FLAGS="%{optflags}" \ + -DCMAKE_CXX_FLAGS="%{optflags}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_SKIP_RPATH=1 \ + .. +make %{?jobs:-j %jobs} + +%install +cd build +make install DESTDIR=$RPM_BUILD_ROOT +cd .. + +%clean +rm -rf "$RPM_BUILD_ROOT" + +@CLEAN@ + +%files +%defattr (-, root, root) +%{_libdir}/YaST2/plugin/libpy2lang_ruby.so +%{_libdir}/ruby/vendor_ruby/%{rb_ver}/%{rb_arch}/yast.so -- 2.39.2