Rubymotion support for ruby 2.0 keyword arguments - rubymotion

Does Rubymotion support ruby 2.0 keyword arguments? I have this method and it throws this error: syntax error, unexpected tSTRING_BEG, expecting tIDENTIFIER
def foo(message, offset: 20)
# Do something
end
I am using the following version of Ruby, but it doesnt seem to be working?
$ ruby -v
vruby 2.0.0p353 (2013-11-22 revision 43784) [x86_64-darwin13.0.2]

No.
RubyMotion was released before Ruby 2.0.0, but it needed keyword arguments to interoperate with Objective-C, for example to define callback/delegate methods. So it introduced keyword arguments based on one of existing keyword arguments proposals at the time:
def tableView(view, numberOfRowsInSection: section)
# ...
end
So in RubyMotion the argument keyword name (numberOfRowsInSection) is separate from the argument name (section), and if keyword is present in a signature, then it is required.
However, Ruby 2.0.0 decided to stick to a different design:
def foo(message, offset: 0)
# ...
end
Argument keyword name is the same as the argument name (offset), they always have a default value (0 here), and they are optional (you can call foo(message) without offset here).
This is a bit unfortunate. But I'm interested to see how will RubyMotion evolve to support Ruby 2.0.0 keyword arguments in future.

Yes.
Using the Ruby Motion developer center docs as a reference, here's an example that looks a lot like what you're trying to do.
class DrawingProxy
def drawAtPoint(point, withFont:font)
#str.drawAtPoint(point, withFont:font)
end
end
That link explains how Objective-C messages with selectors map to and from RubyMotion, which takes things in a slightly non-Ruby direction in that you can effectively have Ruby methods with identical names "overloaded" as long as they have unique selectors (arguments).
A more RubyMotion way to express your example is:
def foo(message, withOffset = 20)
# Do something
end
You were using ":" (call value) rather than "=" (declare default) syntax.

Related

Specify typing for Django field in model (for Pylint)

I have created custom Django model-field subclasses based on CharField but which use to_python() to ensure that the model objects returned have more complex objects (some are lists, some are dicts with a specific format, etc.) -- I'm using MySQL so some of the PostGreSql field types are not available.
All is working great, but Pylint believes that all values in these fields will be strings and thus I get a lot of "unsupported-membership-test" and "unsubscriptable-object" warnings on code that uses these models. I can disable these individually, but I would prefer to let Pylint know that these models return certain object types. Type hints are not helping, e.g.:
class MealPrefs(models.Model):
user = ...foreign key...
prefs: dict[str, list[str]] = \
custom_fields.DictOfListsExtendsCharField(
default={'breakfast': ['cereal', 'toast'],
'lunch': ['sandwich']},
)
I know that certain built-in Django fields return correct types for Pylint (CharField, IntegerField) and certain other extensions have figured out ways of specifying their type so Pylint is happy (MultiSelectField) but digging into their code, I can't figure out where the "magic" specifying the type returned would be.
(note: this question is not related to the INPUT:type of Django form fields)
Thanks!
I had a look at this out of curiosity, and I think most of the "magic" actually comes for pytest-django.
In the Django source code, e.g. for CharField, there is nothing that could really give a type hinter the notion that this is a string. And since the class inherits only from Field, which is also the parent of other non-string fields, the knowledge needs to be encoded elsewhere.
On the other hand, digging through the source code for pylint-django, though, I found where this most likely happens:
in pylint_django.transforms.fields, several fields are hardcoded in a similar fashion:
_STR_FIELDS = ('CharField', 'SlugField', 'URLField', 'TextField', 'EmailField',
'CommaSeparatedIntegerField', 'FilePathField', 'GenericIPAddressField',
'IPAddressField', 'RegexField', 'SlugField')
Further below, a suspiciously named function apply_type_shim, adds information to the class based on the type of field it is (either 'str', 'int', 'dict', 'list', etc.)
This additional information is passed to inference_tip, which according to the astroid docs, is used to add inference info (emphasis mine):
astroid can be used as more than an AST library, it also offers some
basic support of inference, it can infer what names might mean in a
given context, it can be used to solve attributes in a highly complex
class hierarchy, etc. We call this mechanism generally inference
throughout the project.
astroid is the underlying library used by Pylint to represent Python code, so I'm pretty sure that's how the information gets passed to Pylint. If you follow what happens when you import the plugin, you'll find this interesting bit in pylint_django/.plugin, where it actually imports the transforms, effectively adding the inference tip to the AST node.
I think if you want to achieve the same with your own classes, you could either:
Directly derive from another Django model class that already has the associated type you're looking for.
Create, and register an equivalent pylint plugin, that would also use Astroid to add information to the class so that Pylint know what to do with it.
I thought initially that you use a plugin pylint-django, but maybe you explicitly use prospector that automatically installs pylint-django if it finds Django.
The checker pylint neither its plugin doesn't check the code by use information from Python type annotations (PEP 484). It can parse a code with annotations without understanding them and e.g. not to warn about "unused-import" if a name is used in annotations only. The message unsupported-membership-test is reported in a line with expression something in object_A simply if the class A() doesn't have a method __contains__. Similarly the message unsubscriptable-object is related to method __getitem__.
You can patch pylint-django for your custom fields this way:
Add a function:
def my_apply_type_shim(cls, _context=None): # noqa
if cls.name == 'MyListField':
base_nodes = scoped_nodes.builtin_lookup('list')
elif cls.name == 'MyDictField':
base_nodes = scoped_nodes.builtin_lookup('dict')
else:
return apply_type_shim(cls, _context)
base_nodes = [n for n in base_nodes[1] if not isinstance(n, nodes.ImportFrom)]
return iter([cls] + base_nodes)
into pylint_django/transforms/fields.py
and also replace apply_type_shim by my_apply_type_shim in the same file at this line:
def add_transforms(manager):
manager.register_transform(nodes.ClassDef, inference_tip(my_apply_type_shim), is_model_or_form_field)
This adds base classes list or dict respectively, with their magic methods explained above, to your custom field classes if they are used in a Model or FormView.
Notes:
I thought also about a plugin stub solution that does the same, but the alternative with "prospector" seems so complicated for SO that I prefer to simply patch the source after installation.
Classes Model or FormView are the only classes created by metaclasses, used in Django. It is a great idea to emulate a metaclass by a plugin code and to control the analysis simple attributes. If I remember, MyPy, referenced in some comment here, has also a plugin mypy-django for Django, but only for FormView, because writing annotations for django.db is more complicated than to work with attributes. - I was trying to work on it for one week.

Python 2.7 type hinting callable types in PyCharm

I'm trying to use type hinting in python 2.7 as described here.
I have a function that expects a callable (a function) with a specific signature as a parameter and I can't figure out how to annotate it.
I've tried
def set_function(self, function):
# type: ((int) -> None) -> None
But PyCharm shows an expected ')' and unexpected tokens errors
I can't seem to find any documentation for this...
The correct way to document a callable within Pycharm (or within any other tool that understands PEP 484 type hints) is like so:
from typing import Callable
def set_function(self, function):
# type: (Callable[[int], None]) -> None
...
Since you're using Python 2, you'll need to install the typing module from PyPi, if you haven't already. (typing was added to Python's standard library in 3.5, the module on PyPi is a backport).
You can find more information on using the typing module in Python's documentation, and within the documentation for mypy.
(If you're not aware, mypy is a command line tool that also understands PEP 484 type hints and will also statically analyze and typecheck your code. It is an independent effort from Pycharm's built-in type checker. Since both Pycharm and mypy use PEP 484 types, mypy's documentation is often a good place to start looking to learn more about using type hints.)

RLMRealm(path:) Argument labels '(path:)' do not match any available overloads

I just tried to install the latest version of Realm (2.1.0) for Swift 3 and I'm getting an error on this line: let realm = RLMRealm(path: databasePath) - DataManager.swift:258:21: Argument labels '(path:)' do not match any available overloads
The declaration of the argument is here:
var databasePath : String
I know that swift 3 is requiring label for the first argument, but I've looked everywhere for the replacement and can't find an answer.
+ [RLMRealm realmWithPath:] was an API that was deprecated and entirely removed from Realm many months ago. It was replaced with + [RLMRealm realmWithConfiguration:], where you supply an RLMRealmConfiguration object with the file path to the target file set in its fileURL property.
let configuration = RLMRealmConfiguration.defaultConfiguration()
configuration.fileURL = URL(path: databasePath)
let realm = RLMRealm(configuration: configuration)
On a side note, unless you've got a specific reason for using the Objective-C version of Realm in Swift, I highly recommend you use the native Swift version of Realm instead. That one should be a lot easier, and feel a lot more natural in Swift 3. :)

Multiple arguments in bottle's route

In bottle, the route like this:
#get('/ws/contacts/:uid')
how can i add more arguments to the route, and how to code the #get() ?
Just use multiple wildcards:
#get('/ws/contacts/:uid/:itemid')
def get_user_item(uid, itemid):
return 'you passed in uid={} and itemid={}'.format(uid, itemid)
P.S., You're using a deprecated wildcard syntax. Unless you're required to use an old version of Bottle (0.9 or earlier), I recommend that you use the modern syntax, like this:
#get('/ws/contacts/<uid:int>/<itemid:int>')

Using Type-safe URLs with setMessage? (shamlet versus hamlet)

How do I use a type-safe url with setMessage?
I want to change
...
setMessage [shamlet|<span .warning>Warning! See Help.|]
...
to a message that contains a link.
From what I could gather thus far, it ought to work somehow like this
...
renderer <- getUrlRender
let html = [hamlet|<span .warning>Warning! See #
<a href=#{HelpR}> Help!|]
setMessage $ toHtml $ html renderer
...
but that code just gives me confusing error messages all over the file.
I did read the printed Yesod Book Chapter on Shakespearian Templates, but I found that it is not very explicit on the involved types. For instance what type does [hamlet|...|]| produce? Without URL-Interpolation, ghci reports t -> Markup but with URL-Interpolation inside, I just get errors.
I am further confused by all the type synonyms involved, e.g. [shamlet|...|] delivers something of type Html, while setMessage expects a Html (). I do not know how to look these up easily: Hoogle often finds nothing on the topic, while Google always finds possibly outdated versions (with examples that no longer work) - sure I get to the newest version eventually, but is there a place where I get an easy overview over these? (Can ghci list all synonyms for a type?)
Note that I actually want to produce the message in a purely functional code fragment, which is later on used by a handler. So that is why I would like to separate the URL rendering from where the hamlet is specified. Thanks for any pointer in the right direction!
I think you want to use getUrlRenderParams. Strangely enough, a related discussion came up on IRC today. Hamlet templates take a URL rendering function as their first argument, and that function must take two parameters: a type-safe URL, and a list of query string parameters. getUrlRender returns a function that doesn't take the query string parameters, which is why you need getUrlRenderParams instead.