Download & Extend

Turn hook names in theme() and module_invoke() into links

Project:API
Version:6.x-1.x-dev
Component:User interface
Category:feature request
Priority:major
Assigned:tim.plunkett
Status:postponed

Issue Summary

In Drupal 6, the theme() function has become more complex. In D5, <?php theme('foo');?> used to call theme_foo(), but in D6, that is not necessarily true. This makes it harder to look up the code which returns the value for theme('foo').

Take theme_blocks() for instance (http://api.drupal.org/api/function/theme_blocks/6). It contains the following line:

      $output .= theme('block', $block);

The word 'theme' is nicely linked to http://api.drupal.org/api/function/theme/6, but what I'd really like to see documented here, is that the default code for this theme function can be found on http://api.drupal.org/api/file/modules/system/block.tpl.php/6/source. Would it be possible to enhance the UI, so that not only a link to the theme() documentation is provided, but also a link to the function or template that is called by theme('foo')?

Comments

#1

Project:Drupal.org infrastructure» API
Version:<none>» master
Component:Other» User interface

Yes, these links would be nice to have.

#2

Title:api.drupal.org: link to theme() documentation directly» link to theme_...() documentation directly

#3

Thanks for moving the topic, I wasn't sure where to put it.

#4

Would this feature also include linking the code "theme('foo', ...)" to the theme_foo page?
That would be a huge timesaver!

#5

@ #4: Exactly, that's the idea. The only problem is, someone will have to code it first :-)

#6

I had a look at the parser inc file and it baffled me... turning the string "theme('foo'" into a link is fairly simple, though obviously picking whether to link to the 'theme_foo' page or the preprocess function or the tpl file is an extra complexity -- but where would that code need to go?

#7

#8

Given how complex theme() is in Drupal 7 now that theme('links__node') is a standard way of calling theme()… a patch that did this would have to be quite complex.

#9

JohnAlbin: If there is a mechanism in Drupal which redirects the theme() call to the correct function, couldn't we re-use that to redirect documentation links? I mean, you're right, it is complex, but the logic has already been coded, right?

#10

marcvangend -- exactly

And anyway, it's really not rocket science -- this regex gets them in my D7 codebase:

theme\('(\w+)(__\w+)?'

Like I said above, it's a matter of knowing where to plug that into the code.

#11

api_parse_function_calls() and api_link_code() would need to watch for these.

#12

And just a note that it would need to link to either theme_foo() or foo.tpl.php, or perhaps something completely different, depending on hook_theme() implementations.

It would also be great if the theme_foo() or foo.tpl.php pages would list the calling function that called theme('foo') in the "Functions that call this function" section.

#13

Subscribing. This would be pretty sweet.

#14

Title:link to theme_...() documentation directly» Turn theme hook names in theme('hookname', ...) into links

Here's an idea, in the form of a concrete summary of what I think would be a good and feasible outcome:

In code, you have a function call to:

theme('hook_name', ...);
theme('hookname__second__part', ...);
theme(array('hook_name', 'alternate_hook_name'), ...);

'theme' would still be a link to the theme() function page.

'hook_name', 'alternate_hook_name', etc. would turn into links to the first of these that is found in the database:
- theme_hook_name() function
- hook-name.tpl.php file
In the case of the 'hookname__second__part' hook, we would look for:
- theme_hookname__second__part() or hookname--second--part.tpl.php
- theme_hookname__second() or hookname--second.tpl.php
- theme_hookname() or hookname.tpl.php
In the case of the array, we would do this process for hook_name first, then alternate_hook_name, etc.

In the case that no hook function/template could be found that matches, then we would not show a link.

It could be argued that we should try to do something more complicated -- hook_theme() has the ability to define totally unconnected names for the functions/templates. However, I think that case is rare and is probably mostly a bad idea (it leads to overly unreadable code). So let's not worry about that, and concentrate on this idea (which shouldn't be too impossible to implement I think?).

#15

Priority:normal» major

This is kind of related to #745204: Turn strings that are callback function names into function links, but that fix only did strings that are function names, with no special Drupal logic. So this would still be cool to do. It would also be cool if module_invoke(name_of_hook) would turn name_of_hook into a link to hook_name_of_hook, which is more or less the same thing as here, except for hooks instead of theme hooks.

Upping priority (marking "major" things that I'd like to see addressed sooner rather than later).

#16

@jhodgdon: You've obviously got a grasp on how this module does its thing; any chance you could pad out its documentation so others can lend a hand with issues like this? I tried a while back and just couldn't understand how this operates.

#17

Title:Turn theme hook names in theme('hookname', ...) into links» Turn hook names in theme() and module_invoke() into links

Re #15: good point about module_invoke. Changing the title accordingly.

#18

RE #16 - we've had several new contributors to the API project recently who have figured it out (including myself)... if you have specific suggestions for what needs documentation, please file a separate issue or issues (and you might check the queue and see if any have already been filed).

Anyone who wants to help on this particular issue could look at the patch that was committed in #745204: Turn strings that are callback function names into function links as a starting point. I think the thing to do would be to add another argument to api_link_name() called $use_expanded, and if that is TRUE, in the if statement where it's checking to see if the text is an existing function, add another clause that checks for the existance of hook_$text, theme_$text, etc. It should be an easy change to make.

#19

Oh and you'll need to pass in that parameter only when doing code, just like the existing patch for that other issue did.

#20

Jennifer, thanks for the where-to-start instructions. I'm not sure though why "use_expanded" would be a logical as argument name, but that's probably because I don't understand completely how api.module works.

#21

re #20 - that was just off the top of my head. That function is making links in documentation, and I thought "expanded" was a good description of "make links to functions this might be related to"...

Actually, come to think of it, I'm not sure why we shouldn't just do that as part of the "do strings" part that I added in that other issue -- it really doesn't need a separate parameter, since that is also just for code.

#22

Anyway, if someone wants to take this on, *please* assign to yourself as I'm in "fix a bunch of API issues" mode and I'll just do it probably sometime soon, unless I know someone else wants to.

#23

Assigned to:Anonymous» marcvangend

OK, I'll give it a try.

I haven't installed a Drupal API site before, but according to http://drupal.org/node/425944 and http://www.computerminds.co.uk/articles/setting-drupal-api-site-module-d... it shouldn't be too hard.

#24

I didn't have any trouble following the d.o docs the last time I set one up. If you do have trouble, please file a doc issue in this project, or if you find something that you think is obvious how to fix, edit the page. :)

#25

Version:master» 6.x-1.x-dev

fixing branch (we don't use branch master)

#26

marcvangend tried the idea above and reported to me in IRC that this is probably not the best idea. For instance:

watchdog('cron', ...)

would turn 'cron' into a link to 'hook_cron'. [BAD!]

The false positives on that other issue (where strings were turned into function links if the same exact name exists) were not excessive, but if we try to turn all strings xyz into hook_xyz or theme_xyz or theme.tpl.php links, we'll have a lot more false positives. So this will need to be done in a more careful way -- only turning them into links if we're in module_invoke(), theme(), etc.

#27

So far, I have found that it's really easy to make any string that is a (theme) hook name, for instance 'cron', link to its hook_ or theme_ function if it exists. You would only have to add this to api.module in api_link_name() around line 2270:

  elseif (isset($local_objects[$class_did]['item']['hook_' . $name])) {
    return $prepend . l($text, $local_objects[$class_did]['item']['hook_' . $name]['url'], $local_objects[$class_did]['item']['hook_' . $name]['options']) . $append;
  }
  elseif (isset($local_objects[$class_did]['item']['theme_' . $name])) {
    return $prepend . l($text, $local_objects[$class_did]['item']['theme_' . $name]['url'], $local_objects[$class_did]['item']['theme_' . $name]['options']) . $append;
  }
Unfortunately, this is not good enough. The downside of a simple approach like this, is that in the following line of code (found in drupal_cron_run()), the word 'cron' will also be linked to hook_cron():

watchdog('cron', 'Attempting to re-run cron while it is already running.', array(), WATCHDOG_WARNING);
In this context, linking 'cron' to hook_cron() documentation would make absolutely no sense.

To make this work, api_link_name() needs to be aware of the context of the string it is processing. It should only look for (theme) hooks when the string is the first argument in a module_invoke(), module_invoke_all() or theme() call. Unfortunately, the strings being processed in api_link_name are already taken out of their context, but I'm trying to sole that by adding specific search patterns. To be continued.

#28

I think I nailed it. This patch adds two search patterns to detect potential hook names inside theme(), module_invoke_all() and module_implements() calls. These search patterns use a 'positive lookbehind' regex. If one of the patterns is matched, api_link_name tries to find a matching function name after adding the 'hook_' or 'theme_' prefix to the name.

Unfortunately it's not possible to support module_invoke() in the same way, because module invoke has the $module variable as first argument before the hook name. A PCRE lookbehind can only match a fixed strings, but the $module value is passed in different ways throughout the code (eg. module_invoke($module, ....) and module_invoke($block->module, ...)). Still, I think the patch is worth committing without support for module_invoke.

Looking forward to your reviews.

AttachmentSize
link-hook-names-294218-28.patch 4.38 KB

#29

Status:active» needs review

#30

It would be worth covering 'module_invoke($module, 'hook')' as a special case, since it's probably the most common one.

Is there a way to try the patch out by parsing just one file rather than the whole kaboodle?

#31

joachim, I did consider that, but I didn't get it working so I decided to post the patch without it (already way past midnight :-)). Here is what I tried. Instead of this...

    'code hook name' => '!(?<=module_invoke_all</span>\(|module_implements</span>\()<span class="php-string">\'([a-zA-Z0-9_]+)\'</span>!',
the pattern should look something like this:

    'code hook name' => '!(?<=module_invoke_all</span>\(|module_implements</span>\(|module_invoke</span>\(<span class="php-variable">\$module</span>, )<span class="php-string">\'([a-zA-Z0-9_]+)\'</span>!',
Now that I think of it, maybe I forgot to escape the $ character yesterday, so the code above might actually work.

I don't know of a way to test this, other than installing your own API site following the instructions from http://drupal.org/node/425944. Fortunately, it's not really hard. The code affected by this patch runs on every page request (not on cron), so you can simply test changes by refreshing the page.

#32

It needed the comma and the space that come after the $module too.

I've broken the pattern up for legibility, which I think makes monster regexes much easier to figure out :)

Also:

> The code affected by this patch runs on every page request (not on cron), s

OMG, all these recursive regexes are run on every page view!? O_o

And also, I've filed this for later, as I really think this could do with a clean-up: #1364936: clean up scattered data in _api_link_documentation().

And beyond even that, I wonder if there's a way to process this differently so we don't need the lookbehinds...

AttachmentSize
294218.32.api_.theme-invoke-links.patch 4.68 KB

#33

Thanks for the new patch, I'm going to try it out later today.

> OMG, all these recursive regexes are run on every page view!? O_o
Yes. When cron is running, the information about known function names, contstants, class names etc. is not available (or at least not complete) yet.

#34

Status:needs review» needs work

Thanks!

Joachim: We don't break up regexps like this ANYWHERE else in core/contrib that I am aware of, and IMO it doesn't really help readability. Can you scrunch them back up? It just takes up a lot of space. Other than that, the patch in #32 looks like it follows our coding standards and conventions.

It also needs a test before I would commit it -- there are unit tests in the api_link_code.test file that can be used as a model -- just needs a few lines there added.

Also, to be complete, we need to link to template files as well as theme functions. E.g., if you call theme('block', ...), it should like to block.tpl.php, and if you call theme('search_result', ...) it should link to search-result.tpl.php. Note that _ has to be changed to - in template file names, so this will require yet another argument to that function. But that will allow us to get rid of the whole theme.php atrocity, such as this "gem" of documentation for a function that does not even really exist:
http://api.drupal.org/api/drupal/developer--theme.php/function/theme_sea...

#35

I break up regexes in module builder.
I think it makes a *huge* improvement to writing them, reading them, debugging them and everything in fact! The only downside is that literal spaces have to be escaped, but it's very much worth it IMO.

Doesn't this look clearer to you at all?

api.module-expanded-regexes-are-clearer!.png

The way the three items in the lookbehind go one per line is a huge advantage I think. It means I could think about adding that third one for module_invoke() without being confused by the rest of the regex and without accidentally breaking it by getting closing parentheses wrong.

Perhaps I'm just easily confused by the scrunched up version when they get longer than a plain old '/foo(bar)/' sort of thing!

AttachmentSize
api.module-expanded-regexes-are-clearer!.png 122.03 KB

#36

I have never seen that done in Core [edit: Or, for that matter, elsewhere in the API module]. Please don't. Thanks!

#37

I find one long line monster regexes pretty painful[*], so if I can't convince you I don't think I'll bother working on this project any more, sorry.

[*] The same with big arrays. Which we break up in Drupal for readability ;)

#38

Joachim, I really appreciate the work you're doing on this project and all other projects you have contributed to. (That's a long list on your profile page!) I understand your efforts to make regexes more readable and I do agree that your formatting is easier to understand. Meanwhile, I also respect and appreciate the fact that Jennifer wants us all to obey the Drupal coding standards. After all, they exist for a reason.

It would be a shame to see you go because of something like code formatting. Would it help you if we try to get some guidelines for regex formatting into the coding standards? That way, everybody wins.

#39

I've seen this other places, can't find them now, but http://api.drupal.org/api/drupal/includes--locale.inc/constant/LOCALE_JS... is one example. I really appreciate when regex is broken up like this.

#40

OK... A line with just | on it doesn't make sense to me though. Can it be just a little more compact? Normally with arrays and long if() statements, we put the operator at the end of the line?

#41

I am also concerned about consistency. If you're going to break up regexps, break up all of them that are nearby in the function in a similar way.

#42

Please continue the discussion about regex formatting in #1365340: Decide on guidelines for regex formatting and let's return to improving api.module here.

#43

Good idea.

So leaving regexp formatting aside, the things that need to be done for this patch:
- Link to tpl.php files (see #34)
- Unit tests for the various cases added to the api_link_code.test tests:
-- theme('...') where there is a theme function
-- theme('...') where there is a theme template and no theme function
-- module_invoke_*

You will probably need to add hook functions, theme functions, and theme template files to the tests/samples directory in order to test these. In which case please run the other tests and verify they are still passing. In particular, this line in api_objects.test (and maybe another one?) will need updates if you add new functions/files:

    $this->assertEqual($count, 26, 'Found ' . $count . ' documentation objects.');

Thanks!

#44

Status:needs work» needs review

Here's my latest patch.

I'm generating links to .tpl.php files now, using the pattern $template_name = str_replace('_', '-', $name) . '.tpl.php';. If there is a theme file for a theme hook (my-themehook.tpl.php), it takes precedence over the theme function (theme_my_themehook()).

For the time being, until there are guidelines telling me how to split long regexes, I'm sticking to single-line format.

Next on our todo list: tests.

AttachmentSize
link-hook-names-294218-44.patch 5.04 KB

#45

This looks good! I've been doing a lot with tests lately, so if that is at all difficult for you to get into, let me know and I can take care of that part. This will be cool!!! And the logic of "use the tpl first" is absolutely right, due to all those stupid "this is not a real function" theme_* functions. Which I plan to get rid of ASAP. :)

#46

Assigned to:marcvangend» Anonymous

I have only a little experience with writing tests, so while in theory I should be able to do it, I'm sure it will cost me a lot of time. If you don't mind writing the tests, I would love to review and test the patch afterwards, and learn a bit more about tests in the process. Thanks!

#47

Assigned to:Anonymous» jhodgdon

Sounds like a plan. :)

#48

I found one thing. I have my PHP warning level set to the most strict possible, and I was getting a ton of:
Notice: Undefined variable: type in _api_link_documentation() (line 2197 of /home/jhodgdon/gitrepos/api/api.module).

That was easy to fix... just set $type = ''; before the switch($stage) in _api_link_documentation()

Anyway, just saying... it's always a good idea to develop with PHP strict turned on. Very enlightening.

#49

Status:needs review» needs work

Also, is this supposed to turn into a link:

module_invoke($mod, 'sample_name', $baz);

where hook_sample_name() exists? Because it isn't... The module_invoke_all() and module_implements() ones are working, but not this one.

#50

Here, before I lose it, are some samples for testing this, to add to the above patch when it is all working...

AttachmentSize
samples.patch 3.34 KB

#51

Re #48: My bad. I usually have strict warnings on, but I forgot when I recently re-installed my lamp stack.

Re #49: No, that's not supposed to turn into a link. It only works if the first argument passed to module_invoke is actually called "$module".We cannot check for just any variable name. It's a shortcoming of pcre lookbehinds.

#52

While we're at it, let's make this work for drupal_alter() as well. I'll try to add that to the patch later today.

#53

RE #51: You mean you can't check for [a-zA-Z_]* instead of the literal "module" for the variable name? Hm. OK. We should change that in the samples then.

RE #52: drupal_alter -- good idea!

See also comment #14 above -- have you handled the theme('hookname__second_part') case? We should add a bit for that into the samples too.

marcvangend: If you haven't done so already, I suggest you install the api/tests/sample directory as a project/branch in your test API site, and look at the sample_in_code_links() function to see if it's all working.

Which brings me to another bug in the current patch: you need to be careful to make sure if the function is not found, that the string is at least left there in the code. This is currently not working. With this code:

  $b = module_invoke_all('nonexistent_hook', $foo);
  $c = theme('nonexistent_theme_hook', $foo);
  foreach (module_implements('nonexistent_hook') as $module) {
    module_invoke($module, 'nonexistent_hook', $foo);
  }

I'm getting the attached screenshot.

So what I did is to go ahead and commit a change that adds to the samples. If you do a git pull, you should get the new samples, and it shouldn't interfere with the patch from above (which needs to be fixed anyway).
http://drupalcode.org/project/api.git/commit/e6f07b6

If you can get the samples to work right, the patch will be ready, I think. :)

AttachmentSize
missingstrings.png 12.46 KB

#54

> RE #51: You mean you can't check for [a-zA-Z_]* instead of the literal "module" for the variable name? Hm. OK. We should change that in the samples then.

This is a limitation of the way the system works at the moment.
I'm not convinced it needs to have this whole recursive kaboodle, and that's what means we have to use a lookbehind, which is in turn what restricts us. Will file another issue on all that -- it's a future rewrite rather than something we can do now.

#55

I think it will be fine as it is, with this minor limitation. Once it is working correctly, that is (see #53).

#56

Completely agree with #54 and #55. A more advanced future version of this module could perhaps overcome the limitations of regex lookbehinds by some kind of hierarchy-aware (is that a word?) parsing, so when processing a string, you can access information about its parents. However that should not stop us from making a huge step forward right now.

All samples are working correctly now! The code theme('hookname__second_part') now links, in order of priority, to hookname--second-part.tpl.php, theme_hookname__second_part(), hookname.tpl.php or theme_hookname(). The non-existent functions were not shown because the fall-back option (return the name without a link) was wrapped in an else{} block. I simply took out the else statement because the fall-back should always run if nothing has been returned yet.

The third case from #14, theme(array('hook_name', 'alternate_hook_name'), ...);, is not covered by this patch. It cannot be done properly because of the regex limitations mentioned before. In this example, we could turn "hook_name" into a link because the lookbehind "theme(array(" is a known, fixed-length string. However we cannot turn "alternate_hook_name" into a link because the value of the first hook name is unknown. It's also worth noting that I have not found a single occurrence of this syntax (outside in-line docs and automated tests) in Drupal 7 core.

AttachmentSize
link-hook-names-294218-56.patch 7.48 KB

#57

> so when processing a string, you can access information about its parents. However that should not stop us from making a huge step forward right now.

It's more that I don't see the need for recursive parsing, at least for a lot of the processing being done here. If we had an a system that does multiple runs through the whole text with preg_replace rather than preg_split we'd gain a lot of power with our regexes.

But yes, I agree absolutely that this should be left for the future and not hold this current work up.

#58

Status:needs work» needs review

Assuming the status on this should now be "needs review"... I'll test it out ... probably not until tomorrow though. Also needs tests to be added before it can be committed, but as we discussed above, I'm willing to take care of the tests.

#59

Yeah, you're completely right. Needs review and news tests... Thanks in advance!

#60

In reply to #57- the reason this is like this is that this code is like this is that we want each section of text to only be processed once. If something has been potentially made into a link, we don't want to process it again. For example, if something is in @link/@endlink, we don't want other stuff to even attempt dealing with it. The unmatched text is passed recursively to try out the next levels. Other ways of tokenizing might be better, especially for code, but that's another issue.

#61

RE #60/57 - marcvangend is right, the if/else clauses above all return things if they matched, so this is probably OK... but it is still a bit confusing.

#62

Status:needs review» needs work

I think this can be done without removing that last else() if you do this. You have, e.g.:

  elseif ($type == 'hook') {
    if (isset($local_objects[$class_did]['item']['hook_' . $name])) {
      return $prepend . l($text, $local_objects[$class_did]['item']['hook_' . $name]['url'], $local_objects[$class_did]['item']['hook_' . $name]['options']) . $append;
    }
  }

Just change it to:

  elseif ($type == 'hook' && isset($local_objects[$class_did]['item']['hook_' . $name])) {
      return $prepend . l($text, $local_objects[$class_did]['item']['hook_' . $name]['url'], $local_objects[$class_did]['item']['hook_' . $name]['options']) . $append;
  }

Right?

I'd also suggest changing this comment:

   // Find potential hook names in marked-up code inside a module_implements()
    // or module_invoke_all() call.

to
    // Find potential hook names in marked-up code inside a module_implements(),
    // module_invoke(), or module_invoke_all() call. Note that module_invoke()
    // must have $module as its first argument for this regular expression to
    // match, which is a bit restrictive.

Anyway, the patch appears to function as desired. So can you make those changes, and then I'll make some tests and get it committed?

#63

Assigned to:jhodgdon» Anonymous

(I'm open to other ideas on the comment change above, but I think the current comment in your patch needs a bit of expansion.)

Also this issue shouldn't be assigned to me yet. :)

#64

I'm trying to understand why the removal of the else{} statement bothers you. I was never officially trained as a programmer, but as far as I'm concerned, there is nothing wrong with this pattern:

<?php
function my_function() {
 
// Gather some variables first, and then...
 
if ($something) {
    return
$something;
  }
  else if (
$something_else) {
    return
$something_else;
  }
  return
$fallback;
}
?>

You're right that the $type == 'hook' part can be easily reduced to a single if-statement instead of two nested if-statements, but it's not that easy once you get to the $type == 'theme' block, because it has a while-loop inside.

If you insist on bringing back the else{} block, I guess we would have to split off the stuff inside the $type == 'theme' into a separate helper function (eg. _api_match_theme_hook()) and do something like this (untested code, but I think you get the idea):

<?php
 
...
  elseif (
$type == 'theme' && $theme_link = _api_match_theme_hook($name, $local_objects[$class_did]['item'])) {
    return
$prepend . $theme_link . $append;
  }
  ...
?>

<?php
function _api_match_theme_hook($name, $items) {
 
// Iteratively strip everything after the last '__' delimiter, until an
  // implementation is found.
 
$hook_elements = explode('__', $name);
  while (
count($hook_elements) > 0) {
   
$hook = implode('__', $hook_elements);
   
$template_name = str_replace('_', '-', $hook) . '.tpl.php';
   
$function_name = 'theme_' . $hook;
    if (isset(
$items[$template_name])) {
      return
l($text, $items[$template_name]['url'], $items[$template_name]['options']);
    }
    elseif (isset(
$items[$function_name])) {
      return
l($text, $items[$function_name]['url'], $items[$function_name]['options']);
    }
   
array_pop($hook_elements);
  }
}
?>

#65

I would either go with this pattern:

if() {
return something;
}
if {
return something;
}

or this pattern:

if {
}
elseif {
}
else {
}

The way it is now in your patch is not parallel -- kind of a mixture. Besides which:

+  elseif ($type == 'hook') {
+    if (isset($local_objects[$class_did]['item']['hook_' . $name])) {
+      return $prepend . l($text, $local_objects[$class_did]['item']['hook_' . $name]['url'], $local_objects[$class_did]['item']['hook_' . $name]['options']) . $append;
+    }
+  }

This is not necessarily returning something, yet we don't want what used to be the else() to happen, do we?

#66

And no, no need to try to munge the theme part into a single if().

#67

Oh wait. I do see what you're saying -- you do want the former else{} bit to run if nothing has been returned yet.

So. I guess it's OK. Just fix that comment...

#68

Ok, thanks for the feedback, I'll correct the comment later today.

You're right that we do need the former else-bit to run whenever there has not been a return earlier, so that was the reason to remove the else{}. I tried to explain that in the "// Fallback: ..." comment, but it seems that isn't clear enough, otherwise we wouldn't been having the discussion above. Do you have any suggestions how we can improve that comment?

#69

When I'm coding, I often put something like:

// If we get here, none of the above conditions has processed this link. blah blah blah.

#70

Status:needs work» needs review

Here's a new patch with an improved comment for the 'code hook name' regex. I altered your suggested comment a little bit because I also wanted to cause of the restriction. I ended up with:

    // Find potential hook names in marked-up code inside a module_implements(),
    // module_invoke(), or module_invoke_all() call. Note that module_invoke()
    // must have $module as its first argument for this regular expression to
    // match. This is due to a restriction in PCRE lookbehinds.
AttachmentSize
link-hook-names-294218-69.patch 7.67 KB

#71

I'm glad you altered my suggestion and added that additional information. :)

I'm really busy the next few days, but I'll try to get this reviewed and tests written next week. Thanks!

#72

My comment #70 crossed your #69, but thanks for the tip. I made the comment before the fallback part a bit more verbose:

  // Fallback: if we get here, no matching documentation link has been found, so
  // nothing has been returned yet. Return the non-linked text.
This change is in the first patch.

I'm also adding a second patch because I found the actual code for the fallback longer than necessary. The current code is:

<?php
  $ret
= '';
  if (isset(
$prepend_if_not_found)) {
   
$ret .= $prepend_if_not_found;
  }
  else {
   
$ret .= $prepend;
  }
 
$ret .= $text;
  if (isset(
$append_if_not_found)) {
   
$ret .= $append_if_not_found;
  }
  else {
   
$ret .= $append;
  }
  return
$ret;
?>

The following code does exactly the same, but it's more compact and more readable IMHO:
<?php
 
if (isset($prepend_if_not_found)) {
   
$prepend = $prepend_if_not_found;
  }
  if (isset(
$append_if_not_found)) {
   
$append = $append_if_not_found;
  }
  return
$prepend . $text . $append;
?>
AttachmentSize
link-hook-names-294218-72.patch 7.73 KB
link-hook-names-294218-72-2.patch 7.66 KB

#73

Status:needs review» fixed

This is very nice (the 2nd patch). THANKS!!

Besides being very nice code, it also works, which is always a plus. And doesn't throw any PHP warnings, even with strict mode. :)

So it just needs some tests. Which I have written. I also made a miniscule change in the sample file, and committed pushed the whole thing -- see commit for diff:
http://drupalcode.org/project/api.git/commit/5ac47d7

Great work!

marcvangend: If you're interested in doing more with the API module, I have recently prioritized several issues as "major" to indicate I'd really like to see them fixed. I'm not necessarily indicating by that that I think they are easy, but they are my favorites. Your contributions would be welcome on any of those, or any other API issue you'd like to tackle. :)

#74

Awesome, thanks. It's nice to see that I've learned enough the past couple of years to fix my own feature requests :-) I'll have a look at the rest of the API queue.

By the way, do you have any idea when this will reach api.drupal.org?

#75

I don't have a deploy date at the moment. I'd like to get a couple more UI improvements done, make a new release of the module, and then deploy. Hopefully sometime soon after the start of the new year?

#76

Status:fixed» closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

#77

Status:closed (fixed)» active

I just realized maybe we should reopen this to add a few more specific Drupal-isms, such as:
_field_invoke('delete', $entity_type, $entity); ==> links to hook_field_delete()

There are quite a few other functions in Drupal 7 with "invoke" in the name:
http://api.drupal.org/api/search/7/invoke
I think node_invoke would be worth taking care of... maybe others too? They need a bit of investigating, but I don't think they would be too hard to do.

#78

#79

Assigned to:Anonymous» tim.plunkett

Going to try and tackle this over the weekend.

#80

Great! Bonus points if you add tests to the link_documentation tests -- you'll need to add to the samples to get those to work.

I also was thinking that many of the *invoke functions work differently in D6 and D7 -- the names of the hooks they are invoking changed. So we probably need this new code to look for any possible hook that might exist (d6 of d7 style) in the current branch that would be invoked.

And if this is too complicated or won't work, we can also just set this back to "fixed" and decide these custom invoke functions are not worth doing. Or just do some. Or only support the D7 hook names. I'll leave it up to you to figure out. :)

#81

#82

Status:active» postponed

I think we should postpone this until we figure out if #1405914: Change code link/reference creation to use Grammar Parser can address it.