Index: libraries.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.module,v
retrieving revision 1.13
diff -u -p -r1.13 libraries.module
--- libraries.module	4 Nov 2010 16:32:25 -0000	1.13
+++ libraries.module	9 Nov 2010 23:11:03 -0000
@@ -9,8 +9,8 @@
 /**
  * Helper function to build paths to libraries.
  *
- * @param $library
- *   The external library name to return the path for.
+ * @param $name
+ *   The machine name of a library to return the path for.
  * @param $base_path
  *   Whether to prefix the resulting path with base_path().
  *
@@ -19,7 +19,7 @@
  *
  * @ingroup libraries
  */
-function libraries_get_path($library, $base_path = FALSE) {
+function libraries_get_path($name, $base_path = FALSE) {
   $libraries = &drupal_static(__FUNCTION__);
 
   if (!isset($libraries)) {
@@ -27,13 +27,13 @@ function libraries_get_path($library, $b
   }
 
   $path = ($base_path ? base_path() : '');
-  if (!isset($libraries[$library])) {
+  if (!isset($libraries[$name])) {
     // Most often, external libraries can be shared across multiple sites, so
     // we return sites/all/libraries as the default path.
-    $path .= 'sites/all/libraries/' . $library;
+    $path .= 'sites/all/libraries/' . $name;
   }
   else {
-    $path .= $libraries[$library];
+    $path .= $libraries[$name];
   }
 
   return $path;
@@ -151,20 +151,106 @@ function libraries_scan_info_files() {
     }
   }
 
-  foreach ($files as $name => $file) {
-    $files[basename($name, '.libraries')] = $file;
-    unset($files[$name]);
+  foreach ($files as $filename => $file) {
+    $files[basename($filename, '.libraries')] = $file;
+    unset($files[$filename]);
   }
 
   return $files;
 }
+
+/**
+ * Helper function to apply a callback to all parts of a library.
+ *
+ * Because library declarations can include variants and versions, and those
+ * version declarations can in turn include variants, modifying e.g. the 'files'
+ * property everywhere it is declared can be quite cumbersome, in which case
+ * this helper function is useful.
+ *
+ * @param $library
+ *   An associative array of library information, passed by reference.
+ * @param $callback
+ *   A callback to apply to each part of the library. This callback should pass
+ *   the passed in library part by reference.
+ */
+function libraries_traverse_library(&$library, $callback) {
+  // Always apply the callback to the top-level library.
+  $callback($library);
+
+  // Apply callback to versions.
+  if (!empty($library['versions'])) {
+    foreach ($library['versions'] as &$version) {
+      // Versions can include variants as well.
+      if (!empty($version['variants'])) {
+        foreach ($version['variants'] as &$version_variant) {
+          $callback($version_variant);
+        }
+      }
+      $callback($version);
+    }
+  }
+
+  // Apply callback to variants.
+  if (!empty($library['variants'])) {
+    foreach ($library['variants'] as &$variant) {
+      $callback($variant);
+    }
+  }
+}
+
+/**
+ * Helper callback to make 'files' property of libraries consistent.
+ *
+ * This turns libraries' file information declared as e.g.
+ * @code
+ * $library['files']['js'] = array('example_1.js', 'example_2.js');
+ * @endcode
+ * into
+ * @code
+ * $library['files']['js'] = array(
+ *   'example_1.js' => array(),
+ *   'example_2.js' => array(),
+ * );
+ * @endcode
+ *
+ * @param $library
+ *   An associative array of library information or a part of it, passed by
+ *   reference.
+ *
+ * @see libraries_info()
+ * @see libraries_traverse_library()
+ */
+function libraries_make_files_consistent(&$library) {
+  $file_types = array();
+  if (isset($library['files'])) {
+    $file_types[] =& $library['files'];
+  }
+  if (isset($library['integration files'])) {
+    foreach ($library['integration files'] as &$integration_files) {
+      $file_types[] =& $integration_files;
+    }
+  }
+  foreach ($file_types as &$files) {
+    foreach (array('js', 'css', 'php') as $type) {
+      if (!empty($files[$type])) {
+        foreach ($files[$type] as $key => $value) {
+          if (is_numeric($key)) {
+            $files[$type][$value] = array();
+            unset($files[$type][$key]);
+          }
+        }
+      }
+    }
+  }
+}
+
 /**
  * Returns information about registered libraries.
  *
  * The returned information is unprocessed, i.e. as registered by modules.
  *
- * @param $library
- *   (optional) The internal name of a library to return registered information
+ * @param $name
+ *   (optional) The machine name of a library to return registered information
  *   for, or FALSE if no library with the given name exists. If omitted,
  *   information about all libraries is returned.
  *
@@ -177,31 +263,31 @@ function libraries_scan_info_files() {
  * @todo Re-introduce support for include file plugin system - either by copying
  *   Wysiwyg's code, or directly switching to CTools.
  */
-function libraries_info($library = NULL) {
+function libraries_info($name = NULL) {
   $libraries = &drupal_static(__FUNCTION__);
 
   if (!isset($libraries)) {
     $libraries = array();
     // Gather information from hook_libraries_info().
     foreach (module_implements('libraries_info') as $module) {
-      foreach (module_invoke($module, 'libraries_info') as $name => $properties) {
+      foreach (module_invoke($module, 'libraries_info') as $machine_name => $properties) {
         $properties['module'] = $module;
-        $libraries[$name] = $properties;
+        $libraries[$machine_name] = $properties;
       }
     }
     // Gather information from .info files.
     // .info files override module definitions.
-    foreach (libraries_scan_info_files() as $name => $file) {
+    foreach (libraries_scan_info_files() as $machine_name => $file) {
       $properties = drupal_parse_info_file($file->uri);
       $properties['info file'] = $file->uri;
-      $libraries[$name] = $properties;
+      $libraries[$machine_name] = $properties;
     }
 
     // Provide defaults.
-    foreach ($libraries as $name => &$properties) {
+    foreach ($libraries as $machine_name => &$properties) {
       $properties += array(
-        'machine_name' => $name,
-        'name' => $name,
+        'machine name' => $machine_name,
+        'name' => $machine_name,
         'vendor url' => '',
         'download url' => '',
         'path' => '',
@@ -213,14 +299,16 @@ function libraries_info($library = NULL)
         'versions' => array(),
         'integration files' => array(),
       );
+      // Make all file declarations consistent.
+      libraries_traverse_library($properties, 'libraries_make_files_consistent');
     }
 
     // Allow modules to alter the registered libraries.
     drupal_alter('libraries_info', $libraries);
   }
 
-  if (isset($library)) {
-    return !empty($libraries[$library]) ? $libraries[$library] : FALSE;
+  if (isset($name)) {
+    return !empty($libraries[$name]) ? $libraries[$name] : FALSE;
   }
   return $libraries;
 }
@@ -260,7 +348,7 @@ function libraries_detect($libraries) {
  */
 function libraries_detect_library(&$library) {
   $library['installed'] = FALSE;
-  $name = $library['machine_name'];
+  $name = $library['machine name'];
 
   // Check whether the library exists.
   if (!isset($library['library path'])) {
@@ -319,7 +407,7 @@ function libraries_detect_library(&$libr
 
   // Check each variant if it is installed.
   if (!empty($library['variants'])) {
-    foreach ($library['variants'] as $name => &$variant) {
+    foreach ($library['variants'] as $variant_name => &$variant) {
       // If no variant callback has been set, assume the variant to be
       // installed.
       if (!isset($variant['variant callback'])) {
@@ -330,15 +418,15 @@ function libraries_detect_library(&$libr
         // and an indexed array of multiple parameters.
         if (isset($variant['variant arguments'][0])) {
           // Add the library as the first argument, and the variant name as the second.
-          $variant['installed'] = call_user_func_array($variant['variant callback'], array_merge(array($library, $name), $variant['variant arguments']));
+          $variant['installed'] = call_user_func_array($variant['variant callback'], array_merge(array($library, $variant_name), $variant['variant arguments']));
         }
         else {
-          $variant['installed'] = $variant['variant callback']($library, $name, $variant['variant arguments']);
+          $variant['installed'] = $variant['variant callback']($library, $variant_name, $variant['variant arguments']);
         }
         if (!$variant['installed']) {
           $variant['error'] = 'not found';
           $variant['error message'] = t('The %variant variant of %library could not be found.', array(
-            '%variant' => $name,
+            '%variant' => $variant_name,
             '%library' => $library['name'],
           ));
         }
@@ -415,17 +503,12 @@ function libraries_load_files($library) 
   foreach (array('js', 'css') as $type) {
     if (!empty($library['files'][$type])) {
       foreach ($library['files'][$type] as $data => $options) {
-        // If the value is not an array, it's a filename and passed as first
-        // (and only) argument.
-        if (!is_array($options)) {
-          // Prepend the library path to the file name.
-          $data = "$path/$options";
-          $options = NULL;
-        }
+        // Prepend the library path to the file name.
+        $data = "$path/$data";
         // In some cases, the first parameter ($data) is an array. Arrays can't
         // be passed as keys in PHP, so we have to get $data from the value
         // array.
-        if (is_numeric($data)) {
+        if (isset($options['data']) && is_array($options['data'])) {
           $data = $options['data'];
           unset($options['data']);
         }
@@ -441,7 +524,7 @@ function libraries_load_files($library) 
 
   // Load PHP files.
   if (!empty($library['files']['php'])) {
-    foreach ($library['files']['php'] as $file) {
+    foreach ($library['files']['php'] as $file => $value) {
       $file_path = DRUPAL_ROOT . '/' . $path . '/' . $file;
       if (file_exists($file_path)) {
         require_once $file_path;
@@ -461,9 +544,12 @@ function libraries_load_files($library) 
  * @param $options
  *   An associative array containing with the following keys:
  *   - file: The filename to parse for the version, relative to the library
- *     path. For example: 'docs/changelog.txt'.
+ *     path. In case the library has a 'path' attribute, this path is not
+ *     prepended to the filepath specified here. That allows for the version
+ *     information to live outside of the path specified in 'path'. For example:
+ *     'docs/CHANGELOG.txt'.
  *   - pattern: A string containing a regular expression (PCRE) to match the
- *     library version. For example: '/@version (\d+)\.(\d+)/'.
+ *     library version. For example: '/@version (\d.+)/'.
  *   - lines: (optional) The maximum number of lines to search the pattern in.
  *     Defaults to 20.
  *   - cols: (optional) The maximum number of characters per line to take into
Index: tests/libraries.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/libraries/tests/libraries.test,v
retrieving revision 1.10
diff -u -p -r1.10 libraries.test
--- tests/libraries.test	4 Nov 2010 16:32:25 -0000	1.10
+++ tests/libraries.test	9 Nov 2010 23:11:03 -0000
@@ -33,6 +33,7 @@ class LibrariesTestCase extends DrupalWe
     // Test that library information is found correctly.
     $library = libraries_info('example_simple');
     $expected = array_merge(libraries_info('example_empty'), array(
+      'machine name' => 'example_simple',
       'name' => 'Example simple',
       'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
       'version callback' => '_libraries_test_return_version',
@@ -50,6 +51,7 @@ class LibrariesTestCase extends DrupalWe
     // Test a library specified with an .info file gets detected.
     $library = libraries_info('example_info_file');
     $expected = array_merge(libraries_info('example_empty'), array(
+      'machine name' => 'example_info_file',
       'name' => 'Example info file',
       'info file' => drupal_get_path('module', 'libraries_test') . '/example/example_info_file.libraries.info',
     ));
