Also adds GUI support.
The system file representation for variable roles is really just an
educated guess. I am going to ask for assistance in confirming the
representation.
Changes after 0.8.0:
+ * New commands:
+
+ - VARIABLE ROLE.
+
* PSPPIRE graphical user interface improvements:
- Syntax windows now parse syntax in "auto" mode, which in practice
should mean that both "batch" and "interactive" syntax now works,
instead of just "interactive" syntax.
+ - The variable pane of data windows now include a Role column.
+
* Notable bug fixes:
- System files written by IBM SPSS 21 are now read without warnings.
@item Custom attributes
User-defined associations between names and values. @xref{VARIABLE
ATTRIBUTE}.
+
+@cindex variable role
+@item Role
+The intended role of a variable for use in dialog boxes in graphical
+user interfaces. @xref{VARIABLE ROLE}.
@end table
@node System Variables
* VARIABLE ALIGNMENT:: Set the alignment for display.
* VARIABLE WIDTH:: Set the display width.
* VARIABLE LEVEL:: Set the measurement level.
+* VARIABLE ROLE:: Set the role that a variable fills in analysis.
* VECTOR:: Declare an array of variables.
* WRITE FORMATS:: Set variable write formats.
@end menu
Currently, this has no effect except for certain third party software.
+@node VARIABLE ROLE
+@section VARIABLE ROLE
+@vindex VARIABLE ROLE
+@display
+VARIABLE ROLE
+ /@var{role} @var{var_list}
+ [/@var{role} @var{var_list}]@dots{}
+@end display
+
+@cmd{VARIABLE ROLE} sets the intended role of a variable for use in
+dialog boxes in graphical user interfaces. Each @var{role} specifies
+one of the following roles for the variables that follow it:
+
+@table @code
+@item INPUT
+An input variable, such as an independent variable.
+
+@item TARGET
+An output variable, such as an dependent variable.
+
+@item BOTH
+A variable used for input and output.
+
+@item NONE
+No role assigned. (This is a variable's default role.)
+
+@item PARTITION
+Used to break the data into groups for testing.
+
+@item SPLIT
+No meaning except for certain third party software. (This role's
+meaning is unrelated to @cmd{SPLIT FILE}.)
+@end table
+
+The PSPPIRE GUI does not yet use variable roles as intended.
+
@node VECTOR
@section VECTOR
@vindex VECTOR
open (MYFILE, ">$tempdir/out.txt");
- foreach $k (keys %$attr)
+ foreach $k (sort (keys (%$attr)))
{
my $ll = $attr->{$k};
print MYFILE "$k =>";
close (MYFILE);
- ok (compare ("$tempdir/out.txt", <<EOF), "Custom Attributes");
+ ok (compare ("$tempdir/out.txt", <<'EOF'), "Custom Attributes");
+$@Role =>0
colour =>blue, pink, violet
nationality =>foreign
size =>large
static void parse_variable_attributes (struct sfm_reader *,
const struct sfm_extension_record *,
struct dictionary *);
+static void assign_variable_roles (struct sfm_reader *, struct dictionary *);
static void parse_long_string_value_labels (struct sfm_reader *,
const struct sfm_extension_record *,
struct dictionary *);
/* The following records use long names, so they need to follow renaming. */
if (extensions[EXT_VAR_ATTRS] != NULL)
- parse_variable_attributes (r, extensions[EXT_VAR_ATTRS], dict);
+ {
+ parse_variable_attributes (r, extensions[EXT_VAR_ATTRS], dict);
+
+ /* Roles use the $@Role attribute. */
+ assign_variable_roles (r, dict);
+ }
if (extensions[EXT_LONG_LABELS] != NULL)
parse_long_string_value_labels (r, extensions[EXT_LONG_LABELS], dict);
close_text_record (r, text);
}
+static void
+assign_variable_roles (struct sfm_reader *r, struct dictionary *dict)
+{
+ size_t n_warnings = 0;
+ size_t i;
+
+ for (i = 0; i < dict_get_var_cnt (dict); i++)
+ {
+ struct variable *var = dict_get_var (dict, i);
+ struct attrset *attrs = var_get_attributes (var);
+ const struct attribute *attr = attrset_lookup (attrs, "$@Role");
+ if (attr != NULL)
+ {
+ int value = atoi (attribute_get_value (attr, 0));
+ enum var_role role;
+
+ switch (value)
+ {
+ case 0:
+ role = ROLE_NONE;
+ break;
+
+ case 1:
+ role = ROLE_INPUT;
+ break;
+
+ case 2:
+ role = ROLE_OUTPUT;
+ break;
+
+ case 3:
+ role = ROLE_BOTH;
+ break;
+
+ case 4:
+ role = ROLE_PARTITION;
+ break;
+
+ case 5:
+ role = ROLE_SPLIT;
+ break;
+
+ default:
+ role = ROLE_NONE;
+ if (n_warnings++ == 0)
+ sys_warn (r, 0, _("Invalid role for variable %s."),
+ var_get_name (var));
+ }
+
+ var_set_role (var, role);
+ }
+ }
+
+ if (n_warnings > 1)
+ sys_warn (r, 0, _("%zu other variables had invalid roles."),
+ n_warnings - 1);
+}
+
static void
check_overflow (struct sfm_reader *r,
const struct sfm_extension_record *record,
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-2000, 2006-2012 Free Software Foundation, Inc.
+ Copyright (C) 1997-2000, 2006-2013 Free Software Foundation, Inc.
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
write_long_string_value_labels (w, d);
- if (attrset_count (dict_get_attributes (d)))
- write_data_file_attributes (w, d);
- write_variable_attributes (w, d);
+ if (opts.version >= 3)
+ {
+ if (attrset_count (dict_get_attributes (d)))
+ write_data_file_attributes (w, d);
+ write_variable_attributes (w, d);
+ }
write_mrsets (w, d, false);
ds_destroy (&s);
}
+static void
+add_role_attribute (enum var_role role, struct attrset *attrs)
+{
+ struct attribute *attr;
+ const char *s;
+
+ switch (role)
+ {
+ case ROLE_NONE:
+ default:
+ s = "0";
+ break;
+
+ case ROLE_INPUT:
+ s = "1";
+ break;
+
+ case ROLE_OUTPUT:
+ s = "2";
+ break;
+
+ case ROLE_BOTH:
+ s = "3";
+ break;
+
+ case ROLE_PARTITION:
+ s = "4";
+ break;
+
+ case ROLE_SPLIT:
+ s = "5";
+ break;
+ }
+ attrset_delete (attrs, "$@Role");
+
+ attr = attribute_create ("$@Role");
+ attribute_add_value (attr, s);
+ attrset_add (attrs, attr);
+}
+
static void
write_variable_attributes (struct sfm_writer *w, const struct dictionary *d)
{
for (i = 0; i < n_vars; i++)
{
struct variable *v = dict_get_var (d, i);
- struct attrset *attrs = var_get_attributes (v);
- if (attrset_count (attrs))
- {
- if (n_attrsets++)
- ds_put_byte (&s, '/');
- ds_put_format (&s, "%s:", var_get_name (v));
- put_attrset (&s, attrs);
- }
+ struct attrset attrs;
+
+ attrset_clone (&attrs, var_get_attributes (v));
+
+ add_role_attribute (var_get_role (v), &attrs);
+ if (n_attrsets++)
+ ds_put_byte (&s, '/');
+ ds_put_format (&s, "%s:", var_get_name (v));
+ put_attrset (&s, &attrs);
+ attrset_destroy (&attrs);
}
if (n_attrsets)
write_utf8_record (w, dict_get_encoding (d), &s, 18);
/* GUI information. */
enum measure measure; /* Nominal, ordinal, or continuous. */
+ enum var_role role; /* Intended use. */
int display_width; /* Width of data editor column. */
enum alignment alignment; /* Alignment of data in GUI. */
type = val_type_from_width (width);
v->alignment = var_default_alignment (type);
v->measure = var_default_measure (type);
+ v->role = ROLE_NONE;
v->display_width = var_default_display_width (width);
v->print = v->write = var_default_formats (width);
attrset_init (&v->attributes);
}
}
+/* Returns a string version of measurement level M, for use in PSPP command
+ syntax. */
+const char *
+measure_to_syntax (enum measure m)
+{
+ switch (m)
+ {
+ case MEASURE_NOMINAL:
+ return "NOMINAL";
+
+ case MEASURE_ORDINAL:
+ return "ORDINAL";
+
+ case MEASURE_SCALE:
+ return "SCALE";
+
+ default:
+ return "Invalid";
+ }
+}
+
/* Returns V's measurement level. */
enum measure
var_get_measure (const struct variable *v)
return type == VAL_NUMERIC ? MEASURE_SCALE : MEASURE_NOMINAL;
}
\f
+/* Returns true if M is a valid variable role,
+ false otherwise. */
+bool
+var_role_is_valid (enum var_role role)
+{
+ switch (role)
+ {
+ case ROLE_NONE:
+ case ROLE_INPUT:
+ case ROLE_OUTPUT:
+ case ROLE_BOTH:
+ case ROLE_PARTITION:
+ case ROLE_SPLIT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Returns a string version of ROLE, for display to a user. */
+const char *
+var_role_to_string (enum var_role role)
+{
+ switch (role)
+ {
+ case ROLE_NONE:
+ return _("None");
+
+ case ROLE_INPUT:
+ return _("Input");
+
+ case ROLE_OUTPUT:
+ return _("Output");
+
+ case ROLE_BOTH:
+ return _("Both");
+
+ case ROLE_PARTITION:
+ return _("Partition");
+
+ case ROLE_SPLIT:
+ return _("Split");
+
+ default:
+ return "Invalid";
+ }
+}
+
+/* Returns a string version of ROLE, for use in PSPP comamnd syntax. */
+const char *
+var_role_to_syntax (enum var_role role)
+{
+ switch (role)
+ {
+ case ROLE_NONE:
+ return "NONE";
+
+ case ROLE_INPUT:
+ return "INPUT";
+
+ case ROLE_OUTPUT:
+ return "TARGET";
+
+ case ROLE_BOTH:
+ return "BOTH";
+
+ case ROLE_PARTITION:
+ return "PARTITION";
+
+ case ROLE_SPLIT:
+ return "SPLIT";
+
+ default:
+ return "<invalid>";
+ }
+}
+
+/* Returns V's role. */
+enum var_role
+var_get_role (const struct variable *v)
+{
+ return v->role;
+}
+
+/* Sets V's role to ROLE. */
+static void
+var_set_role_quiet (struct variable *v, enum var_role role)
+{
+ assert (var_role_is_valid (role));
+ v->role = role;
+}
+
+
+/* Sets V's role to ROLE. */
+void
+var_set_role (struct variable *v, enum var_role role)
+{
+ struct variable *ov = var_clone (v);
+ var_set_role_quiet (v, role);
+ dict_var_changed (v, VAR_TRAIT_ROLE, ov);
+}
+\f
/* Returns V's display width, which applies only to GUIs. */
int
var_get_display_width (const struct variable *v)
}
}
+/* Returns a string version of alignment A, for use in PSPP command syntax. */
+const char *
+alignment_to_syntax (enum alignment a)
+{
+ switch (a)
+ {
+ case ALIGN_LEFT:
+ return "LEFT";
+
+ case ALIGN_RIGHT:
+ return "RIGHT";
+
+ case ALIGN_CENTRE:
+ return "CENTER";
+
+ default:
+ return "Invalid";
+ }
+}
+
/* Returns V's display alignment, which applies only to GUIs. */
enum alignment
var_get_alignment (const struct variable *v)
var_set_value_labels_quiet (new_var, var_get_value_labels (old_var));
var_set_label_quiet (new_var, var_get_label (old_var), false);
var_set_measure_quiet (new_var, var_get_measure (old_var));
+ var_set_role_quiet (new_var, var_get_role (old_var));
var_set_display_width_quiet (new_var, var_get_display_width (old_var));
var_set_alignment_quiet (new_var, var_get_alignment (old_var));
var_set_leave_quiet (new_var, var_get_leave (old_var));
#define VAR_TRAIT_NAME 0x0001
#define VAR_TRAIT_WIDTH 0x0002
-/* Available for reuse: 0x0004 */
+#define VAR_TRAIT_ROLE 0x0004
#define VAR_TRAIT_LABEL 0x0008
#define VAR_TRAIT_VALUE_LABELS 0x0010
#define VAR_TRAIT_MISSING_VALUES 0x0020
bool measure_is_valid (enum measure);
const char *measure_to_string (enum measure);
+const char *measure_to_syntax (enum measure);
enum measure var_get_measure (const struct variable *);
void var_set_measure (struct variable *, enum measure);
enum measure var_default_measure (enum val_type);
+/* Intended usage of a variable, for populating dialogs. */
+enum var_role
+ {
+ ROLE_NONE,
+ ROLE_INPUT,
+ ROLE_OUTPUT,
+ ROLE_BOTH,
+ ROLE_PARTITION,
+ ROLE_SPLIT
+ };
+
+bool var_role_is_valid (enum var_role);
+const char *var_role_to_string (enum var_role);
+const char *var_role_to_syntax (enum var_role);
+
+enum var_role var_get_role (const struct variable *);
+void var_set_role (struct variable *, enum var_role);
+
/* GUI display width. */
int var_get_display_width (const struct variable *);
void var_set_display_width (struct variable *, int display_width);
bool alignment_is_valid (enum alignment);
const char *alignment_to_string (enum alignment);
+const char *alignment_to_syntax (enum alignment);
enum alignment var_get_alignment (const struct variable *);
void var_set_alignment (struct variable *, enum alignment);
DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ATTRIBUTE", cmd_variable_attribute)
DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE LABELS", cmd_variable_labels)
DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE LEVEL", cmd_variable_level)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ROLE", cmd_variable_role)
DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE WIDTH", cmd_variable_width)
DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VECTOR", cmd_vector)
DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WEIGHT", cmd_weight)
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
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
/* Make sure that enough rows are allocated. */
need_rows = 1;
if (flags & ~(DF_DICT_INDEX | DF_VARIABLE_LABELS))
- need_rows += 15;
+ need_rows += 16;
if (flags & DF_VALUE_LABELS)
need_rows += val_labs_count (var_get_value_labels (v));
if (flags & (DF_ATTRIBUTES | DF_AT_ATTRIBUTES))
}
}
- /* Measurement level, display width, alignment. */
+ /* Measurement level, role, display width, alignment. */
if (flags & DF_MISC)
{
- enum measure m = var_get_measure (v);
- enum alignment a = var_get_alignment (v);
+ enum var_role role = var_get_role (v);
tab_joint_text_format (t, 1, r, 2, r, TAB_LEFT,
_("Measure: %s"),
- m == MEASURE_NOMINAL ? _("Nominal")
- : m == MEASURE_ORDINAL ? _("Ordinal")
- : _("Scale"));
+ measure_to_string (var_get_measure (v)));
r++;
+
+ if (role != ROLE_NONE)
+ {
+ tab_joint_text_format (t, 1, r, 2, r, TAB_LEFT,
+ _("Role: %s"), var_role_to_string (role));
+ r++;
+ }
+
tab_joint_text_format (t, 1, r, 2, r, TAB_LEFT,
_("Display Alignment: %s"),
- a == ALIGN_LEFT ? _("Left")
- : a == ALIGN_CENTRE ? _("Center")
- : _("Right"));
+ alignment_to_string (var_get_alignment (v)));
r++;
+
tab_joint_text_format (t, 1, r, 2, r, TAB_LEFT,
_("Display Width: %d"),
var_get_display_width (v));
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2010, 2011, 2013 Free Software Foundation, Inc.
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
while (lex_token (lexer) != T_ENDCMD);
return CMD_SUCCESS;
}
+
+/* Set variables' role */
+int
+cmd_variable_role (struct lexer *lexer, struct dataset *ds)
+{
+ while (lex_match (lexer, T_SLASH))
+ {
+ struct variable **v;
+ size_t nv;
+ enum var_role role;
+ size_t i;
+
+ if ( lex_match_id (lexer, "INPUT"))
+ role = ROLE_INPUT;
+ else if ( lex_match_id (lexer, "TARGET"))
+ role = ROLE_OUTPUT;
+ else if ( lex_match_id (lexer, "BOTH"))
+ role = ROLE_BOTH;
+ else if ( lex_match_id (lexer, "NONE"))
+ role = ROLE_NONE;
+ else if ( lex_match_id (lexer, "PARTITION"))
+ role = ROLE_PARTITION;
+ else if ( lex_match_id (lexer, "SPLIT"))
+ role = ROLE_SPLIT;
+ else
+ return CMD_FAILURE;
+
+ if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
+ return CMD_FAILURE;
+
+ for (i = 0; i < nv; i++)
+ var_set_role (v[i], role);
+ free (v);
+ }
+
+ return CMD_SUCCESS;
+}
VS_MISSING,
VS_COLUMNS,
VS_ALIGN,
- VS_MEASURE
+ VS_MEASURE,
+ VS_ROLE
};
G_DEFINE_TYPE (PsppireVarSheet, psppire_var_sheet, PSPP_TYPE_SHEET_VIEW);
else if (!strcmp (new_text, measure_to_string (MEASURE_SCALE)))
var_set_measure (var, MEASURE_SCALE);
break;
+
+ case VS_ROLE:
+ if (!strcmp (new_text, var_role_to_string (ROLE_NONE)))
+ var_set_role (var, ROLE_NONE);
+ else if (!strcmp (new_text, var_role_to_string (ROLE_INPUT)))
+ var_set_role (var, ROLE_INPUT);
+ else if (!strcmp (new_text, var_role_to_string (ROLE_OUTPUT)))
+ var_set_role (var, ROLE_OUTPUT);
+ else if (!strcmp (new_text, var_role_to_string (ROLE_BOTH)))
+ var_set_role (var, ROLE_BOTH);
+ else if (!strcmp (new_text, var_role_to_string (ROLE_PARTITION)))
+ var_set_role (var, ROLE_PARTITION);
+ else if (!strcmp (new_text, var_role_to_string (ROLE_SPLIT)))
+ var_set_role (var, ROLE_SPLIT);
+ break;
}
}
psppire_dict_view_get_var_measurement_stock_id (var),
NULL);
break;
+
+ case VS_ROLE:
+ g_object_set (cell,
+ "text", var_role_to_string (var_get_role (var)),
+ "editable", TRUE,
+ NULL);
+ break;
}
}
pspp_sheet_view_column_set_cell_data_func (
column, cell, render_var_cell, obj, NULL);
+ add_combo_column (obj, VS_ROLE, _("Role"), 12,
+ var_role_to_string (ROLE_NONE), ROLE_NONE,
+ var_role_to_string (ROLE_INPUT), ROLE_INPUT,
+ var_role_to_string (ROLE_OUTPUT), ROLE_OUTPUT,
+ var_role_to_string (ROLE_BOTH), ROLE_BOTH,
+ var_role_to_string (ROLE_PARTITION), ROLE_PARTITION,
+ var_role_to_string (ROLE_SPLIT), ROLE_SPLIT,
+ NULL);
+
pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
PSPP_SHEET_SELECTION_MULTIPLE);
enum val_type type = var_get_type (var);
int width = var_get_width (var);
enum measure measure = var_get_measure (var);
+ enum var_role role = var_get_role (var);
enum alignment alignment = var_get_alignment (var);
const struct fmt_spec *format = var_get_print_format (var);
name, var_get_label (var));
if (measure != var_default_measure (type))
syntax_gen_pspp (s, "VARIABLE LEVEL %ss (%ss).\n",
- name,
- (measure == MEASURE_NOMINAL ? "NOMINAL"
- : measure == MEASURE_ORDINAL ? "ORDINAL"
- : "SCALE"));
+ name, measure_to_syntax (measure));
+ if (role != ROLE_NONE)
+ syntax_gen_pspp (s, "VARIABLE ROLE /%ss %ss.\n",
+ var_role_to_syntax (role), name);
if (alignment != var_default_alignment (type))
syntax_gen_pspp (s, "VARIABLE ALIGNMENT %ss (%ss).\n",
- name,
- (alignment == ALIGN_LEFT ? "LEFT"
- : alignment == ALIGN_CENTRE ? "CENTER"
- : "RIGHT"));
+ name, alignment_to_syntax (alignment));
if (var_get_display_width (var) != var_default_display_width (width))
syntax_gen_pspp (s, "VARIABLE WIDTH %ss (%d).\n",
name, var_get_display_width (var));
"FirstVariable:";
"ad"; i8 232; "le('23'"; i8 10; "'34'"; i8 10; ")";
"bert('123'"; i8 10; ")";
+ "$@Role('1'"; i8 10; ")";
"/S"; i8 233; "condVariable:";
"xyzzy('quux'"; i8 10; ")";
);
999; 0;
])
for variant in \
- "be c7cae57af35662acec3b945abcf7927c" \
- "le eb6b4ab9c27bfa0daa49bf2770bccb70"
+ "be 7fff0c04f697adf45f55d8be4aaa8712" \
+ "le 7331339199344aa58bc60d7d05d538a7"
do
set $variant
AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
])
AT_DATA([sys-file.sps], [dnl
GET FILE='sys-file.sav'.
-DISPLAY ATTRIBUTES.
+DISPLAY @ATTRIBUTES.
])
AT_CHECK([pspp -o pspp.csv sys-file.sps])
AT_CHECK([cat pspp.csv], [0],
[[Variable,Description,
FirstVariable,Custom attributes:,
+,$@Role,1
,adèle[1],23
,adèle[2],34
,bert,123
SécondVariable,Custom attributes:,
,xyzzy,quux
+Table: Custom data file attributes.
+Attribute,Value
+Attr1[1],Value1
+Attr1[2],'déclaration'
+SécondAttr[1],123
+SécondAttr[2],456
+]])
+ AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+])
+ AT_CHECK([pspp -o pspp.csv sys-file.sps])
+ AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0],
+[[Variable,Description,,Position
+FirstVariable,Format: F8.0,,1
+,Role: Input,,
+,Custom attributes:,,
+,adèle[1],23,
+,adèle[2],34,
+,bert,123,
+SécondVariable,Format: F8.0,,2
+,Custom attributes:,,
+,xyzzy,quux,
+
Table: Custom data file attributes.
Attribute,Value
Attr1[1],Value1
VARIABLE ALIGNMENT x (LEFT)/y (RIGHT)/z (CENTER).
VARIABLE WIDTH x (10)/y (12)/z (14).
VARIABLE LEVEL x (SCALE)/y (ORDINAL)/z (NOMINAL).
+VARIABLE ROLE /INPUT x /TARGET y /BOTH z.
DISPLAY DICTIONARY.
])
AT_CHECK([pspp -o pspp.csv var-display.sps])
Variable,Description,,Position
x,Format: F8.2,,1
,Measure: Scale,,
+,Role: Input,,
,Display Alignment: Left,,
,Display Width: 10,,
y,Format: F8.2,,2
,Measure: Ordinal,,
+,Role: Output,,
,Display Alignment: Right,,
,Display Width: 12,,
z,Format: F8.2,,3
,Measure: Nominal,,
+,Role: Both,,
,Display Alignment: Center,,
,Display Width: 14,,
])
my $attr = $var->get_attributes ();
- foreach my $k (keys %$attr)
+ foreach my $k (sort (keys (%$attr)))
{
my $ll = $attr->{$k};
print "$k =>";
}
]])
AT_CHECK([RUN_PERL_MODULE test.pl], [0],
- [[colour =>blue, pink, violet
+ [[$@Role =>0
+colour =>blue, pink, violet
nationality =>foreign
size =>large
]])