template auto func(Args... args) { return (args || ... );
std::cout << func("str");
Does it compile? What will be the output?
Answers in the article :)
Fold expressions exist in C++ since C++17 and significantly affect how we treat variadic templates. Back in the day, I wrote about fold-expressions as part of the metaprogramming series, but today we will explore the extreme cases of fold-expression usages.
An important disclaimer before we start: In this article, code examples show variadic template usages with arguments passed by value,…
W3D5: Cogitating Upon My Corpus Callosum Alone I Record a Record of Meta-Programming Solo to Encode My Own ActiveRecord
Friday we had our first day coding solo, as opposed to the paired programming exercises in which we usually engage. Our lecture covered meta-programming (writing code which, when executed, writes new methods, essentially code encoding code). We then used meta-programming to encode our own version of the gem we’ve been using to call SQL commands in rails this week, ActiveRecord. The purpose of this would seem to be twofold: we have the opportunity to practice meta-programming, and we gain a much deeper understanding of the functionality of ActiveRecord by having to write the thing ourselves. While at first I was thrilled to plug one of the school monitors into my laptop, put my headphones in, and go at my own pace, it wasn’t long before I began to miss the benefit of a second pair of eyes and cerebral hemispheres to spot mistakes and find new approaches to problems. Having practiced so much, and overcome so many challenges, as a member of a pair, coding alone again was mildly like a lobotomy. Cut off from my other hemisphere, I approached problems in a more brute-force manner, and started to get a little frustrated with the fact that the TA’s had to field (at least) twice as many questions as usual and were therefore (at most) half as available, until it occurred to me to swallow my pride and just ask those working solo around me for guidance to get over a few humps.
I imagine this is good practice for the professional world, as I will often have to code alone, and I need not hesitate to ask others to give my work a fresh set of eyes or help me get unstuck (and indeed to foster relationships in which such interactions are reciprocal)... but I’m looking forward to having a partner again tomorrow.
Moteur de template magique en Ruby, rencontre avec les Bindings !
Dans cette expérimentation, nous allons créer un simple moteur de template en nous efforçant de simplifier son utilisation à l’extrême.
Nous rencontrerons les binding en Ruby et nous en ferons une utilisation pratique !
TL;DR l'ensemble du code de cet article a été compilé en une Rubygem disponible sur Github.
Notre moteur servira à remplacer les expressions entre {{doubles.accolades}} d'un texte par des valeurs. Ces expressions peuvent être un ou plusieurs appels de méthodes successifs.
Notre moteur fera cette interpolation à partir d’un contexte qui peut être n’importe quel objet. (Voir les détails de l'implémentation dans les commentaires du code :)
tiny_template.rb
Le constructeur de la classe TinyTemplate prend une chaine qui contient des accolades à interpoler et sa méthode parse reçoit le contexte. On peut l’utiliser de cette manière :
greeting.rb
> Greeting.new
"Hello JOHN DOE and welcome to My Fancy Website, your email is [email protected]"
Contrairement à l'interpolation standard en Ruby, notre chaine est une valeur et non du code. Nous pouvons l'enregistrer dans une base de données et laisser l'utilisateur la modifier sans s'exposer à des risques de sécurité.
Seules les méthodes publiques et qui ne prennent pas d'arguments peuvent être appelées en chaine.
Se passer du constructeur avec une méthode de classe
Nous pouvons simplifier cette utilisation en passant par une méthode de classe :
tiny_template.rb
Cette méthode de classe instancie TinyTemplate et appelle la méthode d’instance du même nom sur cette nouvelle instance.
greeting.rb
Se passer de parse grâce à une fonction de module
tiny_template.rb
Nous venons de définir une méthode TinyTemplate dans un module inclus en dehors de toute classe ou module. Cela revient à inclure ce module dans Object et rendre ses méthodes universellement accessibles. Nous pouvons dès lors faire :
greeting.rb
Se passer du contexte grâce à la machine à remonter dans le binding !
Nous aimerions rendre le paramètre context optionnel, ou plutôt lui attribuer par défaut la valeur self s'il n'est pas défini.
Or, self à l'intérieur de la méthode TinyTemplate(), ou même à sa lisière dans la définition def TinyTemplate(str, context = self) est différent de celui qu'on retrouve à l'extérieur, au niveau de l'appelant.
La valeur de self et de toutes les variables locales définies dans le contexte, de même que toutes les variables de classe ou d'instances à un point donné du code est ce qu'on appelle un binding.
Rien de bien neuf, hein ? Sauf que Ruby permet de capturer le binding à n'importe quel point du code. Il permet même de le passer à d'autres contextes qui peuvent l'examiner et en extraire des données.
La méthode binding de Kernel, accessible dans tous les objets et dans tous les contextes, permet de capturer le contexte en cours dans une instance de la classe Binding.
Cette classe n'offre cependant aucun moyen de lister ou inspecter les éléments de ce contexte. Elle permet en revanche d'y évaluer (exécuter) une chaine de caractère contenant du code Ruby via eval(). En effet, eval prend un deuxième paramètre qui n'est autre que le binding sur lequel sera faite l'évaluation.
Essayons :
discover_binding.rb
Nous avons dit que la classe Binding ne permet pas de lister les variables d'un contexte donné, mais rien ne nous empêche de le faire de l'extérieur grâce à une série d'eval()s sur les méthodes local_variables, instance_variables et global_variables !
Ces méthodes peuvent être appelées de n'importe quel point de code, pourquoi pas sur un binding capturé ? Essayons :
discover_binding.rb
Au passage, soulignons que eval() prend un troisième et un quatrième paramètre qui sont respectivement le nom du fichier et le numéro de ligne qui seront rapportés. L'usage est d'y passer les constantes "magiques" __FILE__ et __LINE__, ce qui permettra de guider le débogueur vers l'endroit de l'évaluation, en cas d'erreur de syntaxe.
D'après ce qu'on vient d'apprendre, nous pouvons passer le binding de l'appelant à TinyTemplate et utiliser ce binding pour évaluer self.
Et l'appeler ainsi : TinyTemplate(self, binding).
Sauf que cela ne nous a été d'aucune utilité. On a remplacé la variable context par caller_binding et on a dû ajouter un traitement supplémentaire sans rendre optionnel le paramètre context. Il nous faut un moyen d'accéder aux bindings précédents.
Ruby 2 et plus précisément MRI, l'implémentation officielle de Ruby (oui, car il y'en a plusieurs !) a rendu cela possible. Son API debug_inspector peut être utilisée pour remonter dans la pile des bindings précédents.
Rendons le paramètre context de TinyTemplate() optionnel. Dans le cas où il est omis, nous retrouvons le contexte de l’appelant à l'aide de RubyVM::DebugInspector.
tiny_template.rb
À ce point nous pouvons faire :
greeting.rb
Les bindings sont rarement manipulés explicitement en production. Mais la réalité est qu'ils sont partout utilisés dans nos codes. Les blocks Ruby et autres éléments de langages exécutables (procs et lambas) capturent automatiquement le binding où ils sont créés. Ce qui en fait des closures, des fermetures en bon français.
L'exécution de leur code se fait dans un mix entre ce binding capturé automatiquement et celui où ils sont exécutés via .call ou yield.
Le binding d'un proc peut être accédé comme ça : proc{}.binding. Cette syntaxe peut notamment servir à accéder à une information située à l'extérieur d'un block passé à instance_eval.
Mais ce n'est pas là notre sujet. Reprenons maintenant l'expérimentation :
Se débarrasser de “TinyTemplate” grâce aux open classes
Aurions-nous le moyen de raccourcir davantage cette syntaxe ? Oui, en utilisant un objet existant, qui n’est autre que la chaine de caractère du template à parser !
tiny_template.rb
En effet, Ruby nous permet d’ouvrir des classes existantes et d’y ajouter des méthodes :
greeting.rb
Attendez, pour le coup on a dû rétablir .parse, mais pas pour longtemps :
Se (re)débarasser de parse grâce à une méthode-opérateur
.parse c’est six caractères, il y a moyen de les réduire à un (1) seul, qui se placera devant la chaine à parser !
tiny_template.rb
Nous avons aliasé “~” (le caractère tilde, qui sert généralement à inverser le bit logique ou matcher des expressions régulières) à parse. Oui, c’est possible, car en Ruby, les opérateurs ne sont que des méthodes.
Cela peut être fait également pour +, -, /, *, !, |, & et tous les autres opérateurs. Le tilde est un opérateur unaire, il ne prend qu'un seul paramètre, qui se trouve être self dans notre exemple.
Voici donc l'utilisation définitive :
greeting.rb
Conclusion
Je suis particulièrement content d'avoir pu parler des binding sur ce blog, car il est difficile de trouver un exemple real-life utile de leur utilisation directe.
On n'a habituellement pas besoin de s'en préoccuper. C'est les outils de débogage et d'introspection de code comme pry ou better errors qui en font le plus usage.
Cet exercice est aussi une bonne manière de démontrer la puissance du langage Ruby, mieux en tout cas que les 2 + 3 qui donne 42, et autres 3.times{ puts “text” } ou 1.year.from_now !
Sécuriser les appels de commandes système depuis Ruby 2.x, découverte des `refinements`
Il y a pire que les injections SQL, c'est les injections système. Si votre application doit interagir avec des outils en commande, vous encourez de graves danger si vous passez à vos commandes des paramètres issus de sources pas sûres, comme des données utilisateurs.
Dans cet article, nous verrons comment sécuriser l'exécution des commandes tout en évitant les effets secondaires grâce aux refinements.
Privilégier les API et les couches d'abstraction
À cause de ces risques, il est préférable de communiquer avec les différents services via des API, même au sein d'un même système. C'est possible avec ElasticSearch ou Redis par exemple, qui font tout passer par des endpoint sous localhost.
Mais les outils qui proposent des API restent rares, préférez alors une couche d'abstraction en Ruby qui vous évite de préparer manuellement des commandes paramétrées. Et assurez-vous que cette couche gère de manière optimale la sanitization des paramètres.
Si vous ne trouvez pas de couche d'abstraction, écrivez en une si possible, mais laissez la solution de préparer des commandes en dernier recours.
Appeler une commande système en Ruby, divers moyens nuancés
Il existe plusieurs moyens d'exécuter des commandes système en Ruby. S'ils semblent identiques ou interchangeables, il y a des nuances dans leur mode d'exécution et leurs valeurs de retour.
Le module Kernel, inclus dans Object et dont les méthodes sont par conséquent accessibles à tous les objets Ruby, inclut trois méthodes qui exécutent des commandes système : Kernel#`, Kernel#exec, Kernel#system.
1 - Kernel#` (remarquez le petit backstick après le dièse) exécute la commande dans un subshell (un processus enfant) et renvoie la sortie standard de la commande. Cette méthode est appelée via la syntaxe spéciale `commande` mais rien ne nous empêche de l'appeler plus conventionnellement via send.
2 - Kernel#system exécute la commande dans un subshell (comme `) mais renvoie le statut d'exécution, résumé en soit true soit false (ou nil pour les commandes inexistantes). L'exit-code de la dernière commande exécutée reste accessible dans la variable globale $? avant qu'il ne soit remplacé par le code de la prochaine commande système exécutée. system renvoie true uniquement si l'exit code de la commande est de 0.
system se distingue également de ` par la possibilité de recevoir des variables d'environnement et des paramètres supplémentaires.
3 - Kernel#exec exécute la commande en remplaçant le processus actuel. L'exécution de votre code est donc interrompue pour de bon et il n'est pas possible de tester la valeur de retour ni d'inspecter les sorties standards. exec prend les mêmes paramètres que system.
Il existe d'autres moyens d'exécuter des commandes comme IO#popen et Open3#popen3. Ces derniers permettent un contrôle avancé des flux d'entrée de sortie et d'erreurs, mais nous nous intéresserons plus spécialement à Kernel#` pour la suite de cet article.
Sécuriser les commandes avec Shellwords
Sécuriser une commande est très simple : il suffit d'échapper les paramètres de sources pas sûres à l'aide de Shellwords, un module de la bibliothèque standard de Ruby, qui respecte la norme POSIX / SUSv3.
Notons que require 'shellwords' ouvre la classe String pour y insérer des raccourcis commodes. Nous aurions pu faire :
> `grep rails #{ params[:file].shellescape )}`
Mais encore faut-il se souvenir d'échapper chaque paramètre ajouté de chaque appel de fonction. Un seul oublie et tout est compromis. C'est pourquoi nous allons élaborer une solution de tolérance zéro.
Suspecter toutes les commandes
Ouvrons d'abord la class String pour ajouter le moyen de reconnaitre si une chaine est sûre ou non. Utilisons ce moyen pour marquer les chaines échappées comme étant sûres.
secure_shell.rb
Maintenant, nous devons intervenir sur le module Kernel pour désigner qu'il n'accepte que les chaines échappées ou désignées explicitement comme sûres. Faisons celà par monkey patching classique. Le code peut sembler bizarre avec toutes les apostrophes inversées, mais il est pleinement fonctionnel.
secure_shell.rb
Nous allons à présent apporter quelques modifications de la classe String afin de permettre la création de chaines sûres par la concaténation d'autres chaines sûres.
Pour cela, nous ferons du Monkey Patching d'une approche différente : au lieu de renommer et remplacer les méthodes voulues, nous prependront un module avec de nouvelles versions de nos méthodes :
Mais notre solution n'est pas utilisable en l'état. La syntaxe du backstick `cmd` ne prend pas de variable et nous oblige de passer par des interpolations. Après des heures de recherches et de lecture de code C, j'ai conclu que l'interpolation de chaines en Ruby est effectuée en bas niveau sans appeler des méthodes surchargeables de la classe String ou autre. On est en effet en droit de croire que "grep #{params[:keyword]} Gemfile" n'est qu'un sucre syntaxique pour "grep " + params[:keyword] + " Gemfile", mais il n'en est malheureusement rien !
Nous allons donc être forcés d'utiliser la syntaxe send('`', "grep #{params[:keyword].shellescape} Gemfile".shell_safe!) ou créer une autre méthode dans kernel. C'est ce que nous allons faire en aliasant backstick à ` :
Si nous oublions d'échapper l'une des chaine ou d'en désigner explicitement l'une comme étant saine, une exception est soulevée.
> backstick("grep ".shell_safe! + params[:file].shellescape + " Gemfile")
ArgumentError: Unsafe command, please use String#shellescape or String#shell_safe!
Refinements
Notre exemple illustre parfaitement les dangers du monkey patching. En modifiant le comportement des méthodes, on s'expose au risque de compromettre d'autres codes qui les utilisent.
Si les autres dépendances de votre application (gems) font des appels de commandes système, et c'est toujours le cas, des erreurs surgiront de partout.
C'est la problématique que les refinements introduits dès Ruby 2 sont venus combler. Découverte.
Les refinements permettent de limiter les modifications des classes à des scopes définis (module, class, bloc begin ; end, etc.).
Pour les utiliser, nous devons englober toutes nos ouvertures de classes dans un module. Nous devons également changer d'approche pour la réouverture de modules. refine ne marche en effet qu'avec des classes :
secure_shell.rb
La modification des méthodes de Kernel se fait maintenant par la simple inclusion d'un module. Nous n'avons pas besoin d'utiliser prepend ici car nous savons que Kernel est inclut dans Object. Kernel est donc l'un des ancêtres de Objet. Le dernier module inclut dans une classe est placée en tête de liste des ancêtres. SecureShell::KernelMethods passe donc devant Kernel et peut par conséquent utiliser ses méthodes via `super`.
L'utilisation des refinements se fait à l'aide du mot clé using, qui n'est, sans surprise, qu'une méthode de la class Module. Essayons :
> irb
>> $: << '.'
>> require 'secure_shell'
>> "aString".shell_safe?
NoMethodError: undefined method `shell_safe?' for "aString":String
>> begin
>> using SecureShell
>> puts "aString".shell_safe?
>> end
=> false
>> "aString".shell_safe?
NoMethodError: undefined method `shell_safe?' for "aString":String
Nous utilisons irb pour tester notre solution, la première ligne ajoute le dossier en cours au load_path de Ruby, ce qui nous permet de require le code du refinement. Notez comment l'utilisation de la méthode shell.safe? en dehors du bloc begin / end échoue.
Faisons maintenant des appels plus avancés :
> irb
>> $:
>> require 'secure_shell'
>> require 'securerandom'
>> begin
>> using SecureShell
>>
>> backstick('git init '.shell_safe! + SecureRandom.hex(20).shellescape)
>> end
NoMethodError: undefined method `shell_safe?' for "git init ":String
from /Users/Ihcene/aritylabs/secure_shell/secure_shell.rb:48:in `+'
Erreur ! Nous constatons que "git init ".shell_safe! fonctionne mais pas l'appel à shell_safe? situé dans notre surcharge de la méthode :+ de String via SecureShell::StringConcat. Il est vrai que ce module est inclus dans String mais il ne bénéficie pas, lui, du refinement dont il fait pourtant partie. Nous venons d'être témoin du caractère très strict par rapport au scope des Refinements, qui fait leur force.
La solution est d'isoler les méthodes #shell_safe!, #shell_safe? et #shellescape dans un refinement imbriqué, qui sera utilisé dans le refinement global lui-même et dans les scopes qui nécessitent de sécuriser les appels de commandes système :
secure_shell.rb
L'ensemble peut être utilisé sur une classe de cette manière :
gist.id
> Gist.new.create
=> "Initialized empty Git repository in /Users/Ihcene/aritylabs/secure_shell/ecc8984c07440cecfc0badbd02bea560e9c58b1b/.git/\n"
Conclusion
Nous venons de faire la découverte en pratique de la plus importante nouvelle feature de Ruby 2.x. Les refinements nous ont permis de sécuriser l'exécution de commandes système sans prendre le risque d'affecter les autres dépendances.
It's official: C++11 has two meta-programming languages embedded in it! One is based on templates and other one using constexpr. Templates have been extensively used for meta-programming in C++03. C++11 now gives you one more option of writing compile-time meta-programs using constexpr. The capabilities differ, however.
Recently I had a requirement in an application I was working on to add an internal Settings model. By my own standards, I wanted it to be very lightweight and flexible. There are several gems that provide such drop-in functionality, such as https://github.com/Squeegy/rails-settings or https://github.com/railsjedi/rails_config. However, I felt this added an unnecessary dependency to our project for a seemingly simple feature.
Instead, I ventured to create our own ActiveRecord Based Settings Model. I went in knowing that it needed to be lightweight and flexible. The following is a brief walkthrough of how I went about implementing a Settings model that ultimately has one record in the Settings table and leverages Ruby's dynamic programming to create attributes when required.
The Migration
class CreateSettings < ActiveRecord::Migration def change create_table :settings do |t| t.text :preferences t.timestamps end end end
Pretty straightforward here. Only one column in addition to the timestamps, :preferences. This will be a serialized field allowing me to enter in key value pairs in a hash.
The Pseudo-Singleton
I wanted to ensure that there would never be more than one record in the Settings table, but didn't feel the single Settings object would be accessed often enough to warrant a proper Singleton instantiation. Instead, I added the following to the Settings Model:
class Settings < ActiveRecord::Base ... before_create :confirm_singularity ... def confirm_singularity raise Exception.new("A Setting record already exists") if Settings.count > 0 end end
This simple bit of code ensures that an exception will be raised if an attempt to create a Settings beyond the first is made.
Leveraging Method Missing
I wanted to allow that single Settings preferences Hash to not rely on predefined keys. Rather, it would be far more flexible for any key to be set throughout the lifetime of the application. To achieve this I relied upon method_missing:
def self.method_missing(method, *args) method_name = method.to_s super(method, *args) rescue NoMethodError settings = self.first_or_create if method_name =~ /=$/ name = method_name.gsub('=', '') value = args.first settings.preferences[name.to_sym] = value settings.save else settings.preferences[method_name.to_sym] end end
In this method, when a method that is not found is caught by the 'NoMethodError'. Once caught, I first retrieve or create the settings record. This allows for anyone to assign settings without needing to worry about whether a Setting record has been created or not.
From there I employ a regex to determine whether the method sent to Settings is a setter and thus contains a '='. If it is then I parse the name of the method from the method, and assign the value of the key as the first of args. Then I access the settings.preferences Hash and add the key value pair and subsequently save the settings record.
In the case that the method sent to Settings is a getter, then the else statement simple retrieves and returns the value of the key from settings.preferences.
Conclusion
After completing this task of implementing a flexible Settings model. I felt far more comfortable with Ruby's dynamic/meta programming. Of course there is an overhead cost to dynamic programming, but I feel that for something as innocuous as application settings it was worth it.
I encourage anyone reading this to offer comments and criticisms or other examples of where you've done something similar.
3rd straight day of solo work. This whole week has been building variations of Rails projects, so today was a nice change, as we did something a bit more technical. Our old friend meta-programming returned for the day, and it was a welcome sight. The task was to build an itty-bitty ActiveRecord. Exactly two weeks ago, as we were getting up to speed on SQL, we had built a our own ORM, but it was domain-specific and not reusable. Today, we were challenged to build a small framework that could be used to map data of any type from the database into Rails.
250,000. That's how many lines of code ActiveRecord encompasses. Far be it for us to judge, but after completing today's project, that does seem a bit excessive. In 250 lines, I was able to implement the following features:
attribute_setters
belongs_to association
has_many association
has_one_through association
find record
all records
where (search records by single or multiple criteria)
save (with update & create, as appropriate)
This was a more advanced form of meta-programming than I had attempted before, having had my dalliances with it all throughout the week as I tried to spruce up my individual projects. When we reached the has_one_through feature, I really appreciated the step-by-step curation of the materials. Up to that point I had ironed out the framework, more or less, on my own.
What we did today gave us a valuable view into how ActiveRecord does its magic. You could say it tore back the veil on Oz. Word on the street is that next week we may do the same thing to Rails routing: uncover Rails piece by piece until it's no longer magical. With great power comes great responsibility, and once we uncloak the wizard we very well may don his robes. I, for one, would not mind some wizarding in my career.
Week 5, Day 5-7: Ending Rails with a Bang and Embarking on JS
Exercise: ActiveRecord (meta-programming)
Building Active Record Lite
Today's project was the probably the hardest one we've had so far: We built our own lightweight ActiveRecord class. The three main things I got out of this project were:
1) Demystifying Rails associations and truly understand what's happening at the Ruby level.
2) Practice at meta-programming in Ruby; knowing how to use send, define_method, and constantize.
3) Practice with using class inheritance and modules to organize code in a large-scale project. I gained more program architecture intuition as I learned how to use nested classes and module mix-ins to DRY things up.
Enter the Javascript
Next week we start on Javascript, which I'm looking forward to just for the change. This weekend I went through Code Academy's Javascript lessons. It's fun to learn another language after gaining fluency in Ruby. So far, the biggest difference I notice is that Javascript has objects, but no classes. In some ways, Javascript reminds me of my first programming language, which was MATLAB (a very high level language). They both seem to be pass-by-value languages and they both use "function" to define methods. They both are languages in a confined environment (browser and workspace, respectively). These similarities may be very superficial so we'll see in the coming week.