The double_metaphone() function is defined in a PECL extension and as such PHPStorm cannot see it being defined. I wouldn't like to see any warnings about this. I assume I could make PHPStorm treat this function call as defined through some kind of annotation but I don't know how to make this happen.
You need what is called "stub files":
Create a .php file and place it anywhere in your project (be it project itself... or as an External Library (Settings | PHP | Include paths) -- it does not matter, as long as PhpStorm can see it in this project).
Add that function definition as it would be done in PHP itself: describe all parameters, return type etc. and just leave the body of the function empty.
The documentation is optional: it's just the more doc you have the more useful it will be for PhpStorm and you: the IDE can warn you about invalid parameter type, incorrect return type usage, suggest variables of appropriate types when using code completion for that function etc.
That's it
That's exactly how ALL known PHP functions/classes/etc are done in PhpStorm in the first place: just Ctrl + Click on any standard function/class/constant and see it yourself.
An example: how standard bin2hex function is defined (back in 2013):
<?php
/**
* (PHP 4, PHP 5)<br/>
* Convert binary data into hexadecimal representation
* #link http://php.net/manual/en/function.bin2hex.php
*
* #param string $str A character.
* #return string the hexadecimal representation of the given string.
*/
function bin2hex ($str) {}
You can see all current PhpStorm stubs (and other helper files that IDE uses for PHP completion) in this official repo: https://github.com/JetBrains/phpstorm-stubs
Related
I'm using graphql-ruby, and I'd really like to be able to type the dynamic methods that created for things like arguments.
Small example:
class Test
argument :first_argument, String
argument :secondArgument, String, as: second_argument, required: false
def method
puts first_argument.length # this is okay
puts second_argument.length # this is a problem, because it can be nil
end
end
I've tried to define these by doing:
# ...
first_argument = T.let(nil, String)
second_argument = T.let(nil, T.nilable(String))
which doesn't seem to work. I also did
#...
sig { returns(String) }
def first_argument; ""; end
sig { returns(T.nilable(String)) }
def second_argument; end
which works, but is not overly pretty. Is there a nicer way to go about this?
There is some nascent, experimental support for typing methods declared by meta programming like this: https://sorbet.org/docs/metaprogramming-plugins
In this case, you might define a plugin file like:
# argument_plugin.rb
# Sorbet calls this plugin with command line arguments similar to the following:
# ruby --class Test --method argument --source "argument :first_argument, String"
# we only care about the source here, so we use ARGV[5]
source = ARGV[5]
/argument[( ]:([^,]*?), ([^,]*?)[) ]/.match(source) do |match_data|
puts "sig {return(#{match_data[2]})}" # writes a sig that returns the type
puts "def #{match_data[1]}; end" # writes an empty method with the right name
end
I've only included the "getter" for the argument here, but it should be simple to go ahead and write out the sig for the setter method as well. You'd also want to handle all variants of the argument method as I've only handled the one with Symbol, Type arguments. For what it's worth, I'm not sure if the "source" passed in to your plugin would be normalized with parens or not, so I've made the regex match either. I also suspect that this will not work if you pass in the symbol names as variables instead of literals.
We then use a YAML file to tell Sorbet about this plugin.
# triggers.yaml
ruby_extra_args:
# These options are forwarded to Ruby
- '--disable-gems' # This option speeds up Ruby boot time. Use it if you don't need gems
triggers:
argument: argument_plugin.rb # This tells Sorbet to run argument.rb when it sees a call to `argument`
Run Sorbet and pass in the yaml config file as the argument for --dsl-plugins:
❯ srb tc --dsl-plugins triggers.yaml ... files to type check ...
I'd really like to be able to type the dynamic methods that created for things like arguments
Sorbet doesn't support typing dynamic methods like that. But they do provide a T::Struct class that has similar functionality. I did something similar last week for my project and I'll describe what I did below. If T::Struct doesn't work for you, an alternative is writing some code to generate the Sigs that you'd write manually.
My approach is using T::Struct as the wrapper for “arguments” class. You can define args as props in a T::Struct like following:
const for arguments that don’t change
prop for arguments that may change
Use default to provide a default value when no value is given
Use T.nilable type for arguments that can be nil
Building on top of the vanilla T::Struct, I also add support for “maybe”, which is for args that is truly optional and can be nil. IE: when a value is not passed in, it should not be used at all. It is different from using nil as default value because when a value is passed in, it can be nil. If you’re interested in this “maybe” component, feel free to DM me.
I have to write the following code (using Zend\Filter\Inflector):
$inflector = new Inflector(':string');
$inflector->setRules([
':string' => [
new StringToLower(),
new UnderscoreToSeparator(),
new DashToCamelCase(),
new UpperCaseWords(),
]
]);
As you see, it uses 4 times the new keyword, immediately instantiating classes (following Zend Filter Interface). In this case autocomplete works fine, PhpStorm easily found what I wanted typing after new.
But better notation, using factories, is using strings, instead of direct instantiation using new:
$inflector = new Inflector(':string');
$inflector->setRules([
':string' => [
'StringToLower',
'UnderscoreToSeparator',
'DashToCamelCase',
'UpperCaseWords',
]
]);
Is there a way to have autocomplete for those strings? Maybe some annotation hint or something?
Why don't you use UpperCaseWords::class? The resulting value (that will be available during runtime) will be FQN.
I'm not familiar with Zend Framework so I'm just not sure if Zend\Filter\Inflector accepts FQN or it limited to/requires class names only (it should accept FQN ... so user-made classes would also be accepted/it's expected behaviour).
The benefit: refactoring / find usages will also be supported (since this is a piece of code and not just a string).
In any case: class name completion in strings should work since 2017.1.4 (works fine here in current stable 2017.2.4).
You just invoke code completion one more time (e.g. Ctrl + Space twice (or whatever else shortcut you have there on your computer/OS for Code | Completion | Basic)) .. or just use Ctrl + Alt + Space straight away (class name completion).
Obviously, it will work if completion is invoked on the beginning of the string. If it's in the middle/end of it (e.g. "use [CLASS_NAME_EXPECTED_HERE]") -- type whole thing manually or try other completion methods (e.g. Cyclic Expand Word if such class name was already mentioned in current file).
I use a lot of callbacks and I want the editor to detect the type of function callback that is expected by the method, with a specific nr of parameters of specific types.
Right now it just says Function and it can be anything but I want to make it specific, this in IntelliJ.
Intellij (and the family of editors) support the Google Closure Compiler syntax.
So you'd do something like this:
/**
* #param {function(Number, String)} bar
*/
function foo(bar) {};
Note the lowercase f in function.
I have this:
'components'=>array(
'less'=>array(
'class'=>'ext.less.components.LessCompiler',
'forceCompile'=> true, //YII_DEBUG, // indicates whether to force compiling
//'compress'=>false, // indicates whether to compress compiled CSS
//'debug'=>false, // indicates whether to enable compiler debugging mode
'paths'=>array(
'less/style.less'=>'css/style.css',
),
),
If I enable forceCompile my site is extremely slow. I would imagine because it regenerates the css on each page load. My question is around disabling it. If I disable it:
Will any changes I make to style.less not reflect in the browser?
If so, what is the point of Less? Surely it can't actually be used in production then? Or do you disable forceCompile so it only generates it once?
Any clarity on forceCompile would be highly appreciated!
(And yes, I looked all of for a clear explanation... best I could find was this).
First let me tell you what is the point of less:
less is a meta language, so in general terms using less helps you write easily maintainable css, although the "language" used is less syntax. As a common example, you can define variables in less that are compiled to css values according to the other statements in your less file. Or you can use mixins, nesting, inheritance concepts like you would in most other languages that support OOP.
So you write understandable, readable pseudo/meta css code that is converted to actual css upon compilation.
Now the extension:
Even if you disable forceCompile, the changes made in style.less should reflect, because the extension checks if the file was modified (the following lines from LessCompiler.php should convince you about that):
if ($this->forceCompile || $this->hasChanges())
$this->compileAll();
// ...
/**
* Returns whether any of files configured to be compiled has changed.
* #return boolean the result.
*/
protected function hasChanges() {
// ...
$compiled = $this->getLastModified($destination);
// ...
$modified = $this->getLastModified($dir);
// ...
}
/**
* Returns the last modified for a specific path.
* #param string $path the path.
* #return integer the last modified (as a timestamp).
*/
protected function getLastModified($path){
//...
}
So forceCompile will always compile the file(s) you specify in paths, and you should not enable it in production. The hasChanges call should take care of less files that have been modified, and compile them, which as you see above is automatically done by the extension.
I'm writing a maven plugin that has a parameter that's a String[].
Like this:
/**
* #parameter expression="${args}"
*/
protected String[] args;
This can be utilized through the POM like this:
<args>
<arg>arg1</arg>
<arg>arg2</arg>
<args>
But I want to send it in from the command line
-Dargs={arg1, arg2}
Is this possible?
You can't do it directly as far as I know, but it is pretty common practice to accept a delimited String and split that into an array yourself.
For example the maven-site-plugin allows you to specify a comma-delimited String of locales, while the maven-scala-plugin handles this by allowing you to define the arguments with a pipe separator. You can look at the relevant Mojos to see how the argument is processed.
Some example usages below:
site-plugin:
-Dlocales=enGB,frFR
scala-plugin:
-DaddArgs=arg1|arg2|arg3
Update: if you want to handle this more elegantly, you could use maven-shared-io to allow definition of an external descriptor file, then pass the descriptor location as a property. This means a single command-line argument can reference a structure of configuration.
If this sounds like it might work for you, have a look at this answer that describes how to use external descriptors in the properties plugin, or this answer that does similar for the xml-maven-plugin. Or you can just look at the assembly-plugin for ideas.
Latest maven (3.0.3) should works with:
-DaddArgs=arg1,arg2,arg3
To update on #nybon’s answer a bit, it seems
#Parameter(property="your.param")
private List<String> yourParam;
works, at least when using maven-plugin-annotations:3.5 in Maven 3.5.0. Running with
-Dyour.param=val1,val2
sets the list.
According to Sonatype's blog here, if you are a plugin developer and
use Maven 3
and annotate your array/collection type plugin parameter using annotation like:
/** #parameter expression="${args}" */
In this way, the plugin parameter can be processed by Maven automatically and plugin users can provide the plugin array/collection type parameters via CLI using a comma separated system property like mvn myplugin:mygoal -Dargs=a,b,c
The way to specify a list of values via system property, for a plugin depends on how up to date the plugin is.
However, if you are dealing with a proper implemented plugin that is up to date, then the correct way of specifying an array of values to a plugin is via comma separated strings.
Here is a reference:
http://blog.sonatype.com/2011/03/configuring-plugin-goals-in-maven-3/
Here is a quote from the reference:
For many plugin parameters it is occasionally convenient to specify
their values from the command line via system properties. In the past,
this was limited to parameters of simple types like String or Boolean.
The latest Maven release finally allows plugin users to configure
collections or arrays from the command line via comma-separated
strings. Take for example a plugin parameter like this:
Going a little bit further, we can look at more concrete example.
Consider, the Wildfly maven plugin.
This plugin has a deprecated configuration property called:
jvmArgs.
This was expected to be passed in as a space separated list of values.
As we all know, in the command line, messing around with spaces is not adorable.
So if we look at the definition of this paramter in the plugin mojo code, you will find something like this (here goes another quote).
/**
* A space delimited list of JVM arguments.
*
* #deprecated use {#link #javaOpts}
*/
#Parameter(alias = "jvm-args", property = PropertyNames.JVM_ARGS)
#Deprecated
private String jvmArgs;
So this is the old way of doing stuff.
Now, if you are using the latest version of this plugin (e.g. Alpha6).
Then the source code will have a nice new field called javaOpts.
Let us look at what the field looks like in the code.
/**
* The JVM options to use.
*/
#Parameter(alias = "java-opts", property = PropertyNames.JAVA_OPTS)
private String[] javaOpts;
So what we see is that we have a nice array field in the StartMojo.
This array field is properly annoted.
And the maven engine will do the heavy lifting of setting the values into the Mojo.
When you want to pump data into this field via the command line, you would in you batch file specify something of the form:
-Dwildfly.javaOpts="-Xmx1536M,-Xms1536M,-XX:MaxMetaspaceSize=512M,-XX:-HeapDumpOnOutOfMemoryError"
If you try the samething using sapces instead of commans.
I will show you what happens:
[INFO] STANDALONE server is starting up. Invalid maximum heap size:
-Xmx1536M -XX:MaxMetaspaceSize=512m -XX:-HeapDumpOnOutOfMemoryError
So you see, maven when it with swallowed my system property full of spaces it did not do a string split. So Wildfly tried to setup the jvm memory settings as if the max memory was that full string.
On the other hand, when I use commas to separate it, the Mojo is properly enriched and I can take control of the memory settings of the app server when it starts up.
And of course, you want to use system properties and not pom.xml XML configuration, for tasks like setting up Jenkins jobs. With system properties you are rather more flexible.
That is it.