Author: particle
Date: Mon May 14 08:51:01 2007
New Revision: 18538

Modified:
   trunk/src/pmc/exporter.pmc
   trunk/t/pmc/exporter.t

Log:
[pmc]: exporter api changes
~ removed 'add_global' method
~ 'globals' is now getter/setter, matching 'source' and 'destination' method 
semantics
~ added SYNOPSIS with example code

Modified: trunk/src/pmc/exporter.pmc
==============================================================================
--- trunk/src/pmc/exporter.pmc  (original)
+++ trunk/src/pmc/exporter.pmc  Mon May 14 08:51:01 2007
@@ -6,6 +6,24 @@
 
 src/pmc/exporter.pmc - Export globals from one namespace to another
 
+=head1 SYNOPSIS
+
+You can use Exporter in PIR to import subs from a library. At its simplest:
+
+ .sub main :main
+     load_bytecode 'Test/More.pir'
+     .local pmc exporter, test_ns
+     test_ns = get_namespace ['Test::More']
+     exporter = new 'Exporter'
+     exporter.'import'( test_ns :named('source'), 'plan ok' :named('globals') )
+     plan(1)
+     ok(1, 'exporter has imported the requested functions')
+ .end
+
+Fancier options exist which allow you to import to an alternate namespace,
+or export globals so they can be called using a different name. See
+F<t/pmc/exporter.t> for examples.
+
 =head1 DESCRIPTION
 
 Exports globals from one namespace to another. Exporter always uses
@@ -13,7 +31,7 @@
 F<docs/pdds/pdd21_namespaces.pod>.
 
 Exporter is not derived from any other PMC, and does not provide any
-standard interface--its interface consists solely of non-vtable methods.
+vtable interface--its interface consists solely of non-vtable methods.
 
 =head2 Structure
 
@@ -33,7 +51,7 @@
 
 =item C<globals>
 
-The globals to export -- a ResizableStringArray.
+The globals to export -- a PMC that implements the hash interface, or Null.
 A Null PMC is allocated during initialization.
 
 =cut
@@ -156,7 +174,6 @@
                         "source must be a NameSpace PMC");
                 return;
             }
-
             exp->ns_src = src;
         }
         else {
@@ -204,41 +221,76 @@
 =item C<PCCMETHOD void
     globals(PMC *glb :optional, int got_glb :opt_flag)>
 
-Accessor for the array of globals to export (C<globals>.)
-Sets the array if C<glb> is passed, otherwise returns the value.
-If C<glb> is a String, it is split on ascii whitespace.
-If C<glb> is a FixedStringArray, it is cloned and set.
+Accessor for the globals to export (C<globals>.)
+Sets the value if C<glb> is passed, otherwise returns the value.
+If C<glb> is a String, it is split on ascii whitespace, and each array member
+is added as a hash key.
+If C<glb> implements the array interface, each member is added as a hash key.
+if C<glb> implements the hash interface, it is assigned to Exporter's
+C<globals> attribute.
+Throws an exception if an unknown PMC type is passed.
 
 =cut
 
 */
 
     PCCMETHOD void globals(PMC *glb :optional, int got_glb :opt_flag) {
-        Parrot_Exporter *exp = PARROT_EXPORTER(SELF);
-        PMC *ret_globals;
-        STRING *s_str = CONST_STRING(interp, "String");
-        STRING *s_arr = CONST_STRING(interp, "array");
+        Parrot_Exporter *exp    = PARROT_EXPORTER(SELF);
+        PMC             *ret_globals;
+        STRING          *s_str  = CONST_STRING(interp, "String");
+        STRING          *s_arr  = CONST_STRING(interp, "array");
+        STRING          *s_hash = CONST_STRING(interp, "hash");
 
         if (got_glb) {
-            if (PMC_IS_NULL(glb))
-                exp->globals = PMCNULL;
-            else if (VTABLE_isa(interp, glb, s_str))
-                exp->globals = string_split(interp,
-                        CONST_STRING(interp, " "),
-                        VTABLE_get_string(interp, glb));
-            else if (VTABLE_does(interp, glb, s_arr))
-                exp->globals = VTABLE_clone(interp, glb);
-            else
-                 real_exception(interp, NULL, 0,
-                     "Invalid type %d in globals()", glb->vtable->base_type);
+            STRING * const s_empty      = CONST_STRING(interp, "");
+            PMC           *temp_globals = pmc_new(interp, enum_class_Hash);
+
+            if (PMC_IS_NULL(glb)) {
+                temp_globals = PMCNULL;
+            }
+            else if (VTABLE_isa(interp, glb, s_str) || (VTABLE_does(interp, 
glb, s_arr))) {
+                PMC    *glb_array;
+                INTVAL n, i;
+
+                if (VTABLE_isa(interp, glb, s_str))
+                    glb_array = string_split(interp,
+                            CONST_STRING(interp, " "),
+                            VTABLE_get_string(interp, glb));
+                else
+                    glb_array = glb;
+
+                n = VTABLE_elements(interp, glb_array);
+
+                if (n == 0)
+                    temp_globals = PMCNULL;
+
+                for(i = 0; i < n; i++) {
+                    STRING * const item = VTABLE_get_string_keyed_int(interp, 
glb_array, i);
+                    VTABLE_set_string_keyed_str(interp, temp_globals, item, 
s_empty);
+                }
+            }
+            else if (VTABLE_does(interp, glb, s_hash)) {
+                if (VTABLE_elements(interp, glb) == 0)
+                    temp_globals = PMCNULL;
+                else
+                    temp_globals = glb;
+            }
+            else {
+                real_exception(interp, NULL, 0,
+                    "Invalid type %d in globals()", glb->vtable->base_type);
+                return;
+            }
+
+            exp->globals = temp_globals;
          }
          else {
             if (PMC_IS_NULL(exp->globals)) {
                 PCCRETURN(PMC *PMCNULL);
             }
             else {
-                ret_globals = VTABLE_clone(interp, exp->globals);
-                PCCRETURN(PMC *ret_globals);
+                PMC *tmp_globals;
+                tmp_globals = exp->globals;
+                PCCRETURN(PMC *tmp_globals);
             }
         }
     }
@@ -247,37 +299,12 @@
 /*
 
 =item C<PCCMETHOD void
-    add_global(PMC *global :optional, int has_global :opt_flag)>
-
-Add C<global> to the array of globals (C<globals>.)
-Sets the array if C<global> is passed, otherwise does nothing.
-
-=cut
-
-*/
-
-    PCCMETHOD void add_global(PMC *global :optional, int has_global :opt_flag) 
{
-        Parrot_Exporter *exp = PARROT_EXPORTER(SELF);
-        if (has_global) {
-            if (PMC_IS_NULL(exp->globals))
-                exp->globals = pmc_new(interp, 
enum_class_ResizableStringArray);
-
-            VTABLE_push_string(interp, exp->globals,
-                    VTABLE_get_string(interp, global));
-        }
-    }
-
-
-/*
-
-=item C<PCCMETHOD void
     import(PMC *dest :optional :named["destination"], int got_dest :opt_flag,
-        PMC *src :optional :named["source"],      int got_src :opt_flag,
+        PMC *src     :optional :named["source"],  int got_src :opt_flag,
         PMC *globals :optional :named["globals"], int got_globals :opt_flag)>
 
 Import C<globals> from the C<src> namespace to the C<dest> namespace.
-If C<src>, C<dest>, or C<globals> are passed, they will override
-the current value.
+If C<src>, C<dest>, or C<globals> are passed, they override the current value.
 C<import> follows the semantics of the C<export_to> method
 of the C<NameSpace> PMC. in particular, if a NULL value is passed
 for C<globals>, the default set of items will be imported.
@@ -288,7 +315,7 @@
 */
 
     PCCMETHOD void import(PMC *dest :optional :named["destination"], int 
got_dest :opt_flag,
-            PMC *src :optional :named["source"], int got_src :opt_flag,
+            PMC *src     :optional :named["source"],  int got_src :opt_flag,
             PMC *globals :optional :named["globals"], int got_globals 
:opt_flag) {
 
         Parrot_Exporter *exp = PARROT_EXPORTER(SELF);

Modified: trunk/t/pmc/exporter.t
==============================================================================
--- trunk/t/pmc/exporter.t      (original)
+++ trunk/t/pmc/exporter.t      Mon May 14 08:51:01 2007
@@ -6,7 +6,7 @@
 use warnings;
 use lib qw( . lib ../lib ../../lib );
 use Test::More;
-use Parrot::Test tests => 10;
+use Parrot::Test tests => 12;
 
 =head1 NAME
 
@@ -22,6 +22,7 @@
 
 =cut
 
+
 # L<PDD17/Exporter PMC>
 # TODO fix smartlinks once this is specced
 pir_output_is( <<'CODE', <<'OUT', 'new' );
@@ -40,6 +41,7 @@
 ok 2 - isa $P0, 'Exporter'
 OUT
 
+
 pir_output_is( <<'CODE', <<'OUT', 'source' );
 .sub 'test' :main
     new $P0, .Exporter
@@ -92,6 +94,7 @@
 ok 4 - source() with non-namespace arg throws exception
 OUT
 
+
 pir_output_is( <<'CODE', <<'OUT', 'destination' );
 .sub 'test' :main
     new $P0, .Exporter
@@ -151,6 +154,7 @@
 ok 5 - destination() with non-namespace arg throws exception
 OUT
 
+
 pir_output_is( <<'CODE', <<'OUT', 'globals' );
 .sub 'test' :main
     $P0 = new .Exporter
@@ -167,110 +171,84 @@
 
     $P0.'globals'($P99)
     $P1 = $P0.'globals'()
-    $I0 = does $P1, 'array'
-    $I99 = $P99
-    $I1 = $P1
-    unless $I0 == 1 goto nok_2
-    unless $I1 == $I99 goto nok_2
-    unless $I1 == 0 goto ok_2
-    goto ok_2
-  nok_2:
+    $I0 = isnull $P1
+    if $I0 goto ok_2
     print 'not '
   ok_2:
-    say 'ok 2 - globals() with args sets globals array (empty array)'
+    say 'ok 2 - globals() with empty array arg sets PMCNULL'
 
     $P99 = push 'Alex'
     $P99 = push 'Prince'
 
     $P0.'globals'($P99)
     $P1 = $P0.'globals'()
+    $I0 = does $P1, 'hash'
     $I99 = $P99
     $I1 = $P1
+    unless $I0 == 1 goto nok_3
     unless $I1 == $I99 goto nok_3
-    unless $I1 == 2 goto nok_3
-    $S0 = pop $P1
-    unless $S0 == 'Prince' goto nok_3
-    $S0 = pop $P1
-    unless $S0 == 'Alex' goto nok_3
+    unless $I1 == 2 goto ok_3
+    $I0 = exists $P1['Prince']
+    unless $I0 goto nok_3
+    $I0 = exists $P1['Alex']
     goto ok_3
   nok_3:
     print 'not '
   ok_3:
-    say 'ok 3 - globals() with args sets globals array (array with two values)'
-
+    say 'ok 3 - globals() with array arg sets globals hash (hash with two 
keys)'
 
-    $P98 = clone $P99
-
-    push_eh ok_4
-    $P0.'globals'($P99, $P98)
-    clear_eh
+    # create a hash to store globals in
+    $P99 = new .Hash
 
+    $P0.'globals'($P99)
+    $P1 = $P0.'globals'()
+    $I0 = isnull $P1
+    if $I0 goto ok_4
     print 'not '
   ok_4:
-    say 'ok 4 - globals() with too many args fails'
-
-.end
-CODE
-ok 1 - globals() returns PMCNULL upon Exporter init
-ok 2 - globals() with args sets globals array (empty array)
-ok 3 - globals() with args sets globals array (array with two values)
-ok 4 - globals() with too many args fails
-OUT
+    say 'ok 4 - globals() with empty hash arg sets PMCNULL'
 
-pir_output_is( <<'CODE', <<'OUT', 'add_global' );
-.sub 'test' :main
-    $P0 = new .Exporter
+    $P99['Prince'] = ''
+    $P99['Alex'] = ''
 
-    $P0.'add_global'()
+    $P0.'globals'($P99)
     $P1 = $P0.'globals'()
-    if null $P1 goto ok_1
+    $I99 = $P99
+    $I1 = $P1
+    unless $I1 == $I99 goto nok_5
+    unless $I1 == 2 goto nok_5
+    $I0 = exists $P1['Prince']
+    unless $I0 goto nok_5
+    $I0 = exists $P1['Alex']
+    unless $I0 goto nok_5
+    goto ok_5
+  nok_5:
     print 'not '
-  ok_1:
-    say 'ok 1 - add_global() with no args does nothing'
+  ok_5:
+    say 'ok 5 - globals() with hash arg sets globals hash (hash with two keys)'
 
-    $P0.'add_global'('foo')
-    $P1 = $P0.'globals'()
-    $I0 = $P1
-    unless $I0 == 1 goto nok_2
-    $S0 = $P1[0]
-    unless $S0 == 'foo' goto nok_2
-    goto ok_2
-  nok_2:
-    print 'not '
-  ok_2:
-    say 'ok 2 - add_global() with args adds string to globals array'
 
-    $P0.'add_global'('bar')
-    $P1 = $P0.'globals'()
-    $I0 = $P1
-    unless $I0 == 2 goto nok_3
-    $S0 = $P1[0]
-    unless $S0 == 'foo' goto nok_3
-    $S0 = $P1[1]
-    unless $S0 == 'bar' goto nok_3
-    goto ok_3
-  nok_3:
-    print 'not '
-  ok_3:
-    say 'ok 3 - add_global() with args adds string to globals array (again)'
+    $P98 = clone $P99
 
-    push_eh ok_4
+    push_eh ok_6
     $P0.'globals'($P99, $P98)
     clear_eh
 
     print 'not '
-  ok_4:
-    say 'ok 4 - add_global() with too many args fails'
+  ok_6:
+    say 'ok 6 - globals() with too many args fails'
 
 .end
 CODE
-ok 1 - add_global() with no args does nothing
-ok 2 - add_global() with args adds string to globals array
-ok 3 - add_global() with args adds string to globals array (again)
-ok 4 - add_global() with too many args fails
+ok 1 - globals() returns PMCNULL upon Exporter init
+ok 2 - globals() with empty array arg sets PMCNULL
+ok 3 - globals() with array arg sets globals hash (hash with two keys)
+ok 4 - globals() with empty hash arg sets PMCNULL
+ok 5 - globals() with hash arg sets globals hash (hash with two keys)
+ok 6 - globals() with too many args fails
 OUT
 
-## TODO import
+
 pir_error_output_like( <<'CODE', <<'OUT', 'import - no args' );
 .sub 'test' :main
     $P0 = new .Exporter
@@ -287,7 +265,7 @@
 .sub 'test' :main
     .local pmc exporter, src
 
-    src     = get_namespace
+    src      = get_namespace
 
     exporter = new .Exporter
     exporter.'import'( src :named('source'), src :named('destination'), 'plan 
ok' :named('globals') )
@@ -309,12 +287,13 @@
 ok 1
 OUT
 
+
 pir_output_is( <<'CODE', <<'OUT', 'import - globals as string' );
 .sub 'test' :main
     load_bytecode 'Test/More.pir'
     .local pmc exporter, src
 
-    src     = get_namespace ['Test::More']
+    src      = get_namespace ['Test::More']
 
     exporter = new .Exporter
     exporter.'import'( src :named('source'), 'plan ok' :named('globals') )
@@ -326,6 +305,26 @@
 ok 1
 OUT
 
+
+pir_output_is( <<'CODE', <<'OUT', 'import - globals with source passed 
separately' );
+.sub 'test' :main
+    load_bytecode 'Test/More.pir'
+    .local pmc exporter, src
+
+    src      = get_namespace ['Test::More']
+
+    exporter = new .Exporter
+    exporter.'source'( src )
+    exporter.'import'( 'plan ok' :named('globals') )
+    plan(1)
+    ok(1)
+.end
+CODE
+1..1
+ok 1
+OUT
+
+
 pir_output_is( <<'CODE', <<'OUT', 'import - globals as array' );
 .sub 'test' :main
     load_bytecode 'Test/More.pir'
@@ -346,6 +345,50 @@
 ok 1
 OUT
 
+
+pir_output_is( <<'CODE', <<'OUT', 'import - globals as hash - null + empty 
string' );
+.sub 'test' :main
+    load_bytecode 'Test/More.pir'
+    .local pmc exporter, src, globals, nul
+
+    nul     = new .Null
+    src     = get_namespace ['Test::More']
+    globals = new .Hash
+    globals['ok'] = nul
+    globals['plan'] = ''
+
+    exporter = new .Exporter
+    exporter.'import'( src :named('source'), globals :named('globals') )
+    plan(1)
+    ok(1)
+.end
+CODE
+1..1
+ok 1
+OUT
+
+
+pir_output_is( <<'CODE', <<'OUT', 'import - globals as hash - with dest names 
(latin)' );
+.sub 'test' :main
+    load_bytecode 'Test/More.pir'
+    .local pmc exporter, src, globals
+
+    src     = get_namespace ['Test::More']
+    globals = new .Hash
+    globals['plan'] = 'consilium'
+    globals['ok'] = 'rectus'
+
+    exporter = new .Exporter
+    exporter.'import'( src :named('source'), globals :named('globals') )
+    consilium(1)
+    rectus(1)
+.end
+CODE
+1..1
+ok 1
+OUT
+
+
 pir_output_is( <<'CODE', <<'OUT', 'import - globals with destination' );
 .sub 'test' :main
     load_bytecode 'Test/More.pir'
@@ -374,6 +417,10 @@
 ok 1
 OUT
 
+
+# TODO test exporting mmd subs
+
+
 # Local Variables:
 #   mode: cperl
 #   cperl-indent-level: 4

Reply via email to