metaprogramming


Programmatically alter Elixir Code


I need to load, alter and write the code in a mix.exs file. I want to be able to load the file, write the dependencies and write the file.
I start with:
defmodule Elixir_2ndTest.Mixfile do
use Mix.Project
def project do
[app: :elixir_2nd_test,
version: "0.0.1",
elixir: "~> 1.2",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
description: description(),
deps: deps]
end
def application do
[applications: [:logger]]
end
defp deps do
[]
end
end
And I need to end up with (the only difference is in the deps fun):
defmodule Elixir_2ndTest.Mixfile do
use Mix.Project
def project do
[app: :elixir_2nd_test,
version: "0.0.1",
elixir: "~> 1.2",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
description: description(),
deps: deps]
end
def application do
[applications: [:logger]]
end
defp deps do
[{:httpoison, "~> 0.8.3"}]
end
end
The dependencies come from a different build system (I cannot use hex directly form the public internet, so I use it in OFFLINE mode and drop the dependencies in .hex/
I know what teh depenencies and what the versions are an need to insert them in the deps function (in this case httpoison 0.8.3).
If my understanding is correct this should be possible by loading the file, quoting, altering, unquoting.
This is what I have up until this point:
{:ok, body} = File.read("mix.exs")
{:ok, ast} = Code.string_to_quoted(body)
Any pointer on how I can alter the ast and write it back would be appreciated.
It won't look exactly the same, but you can use Macro.to_string to convert the ast back to elixir code.
I was playing around with using my library PhStTransform to modify the ast and convert it back to code. Here's a very simple example from the PhStTransform test library.
test "transform quote do output" do
data = quote do: Enum.map(1..3, fn(x) -> x*x end)
data_transform = quote do: Enum.map(1..3, fn(y) -> y*y end)
replace_x = fn(a, _d ) ->
case a do
:x -> :y
atom -> atom
end
end
potion = %{ Atom => replace_x }
assert PhStTransform.transform(data, potion) == data_transform
end
What that does is convert all references to :x in the ast into :y. You'd need to be a bit more clever with writing the potion for PhStTransform, but I think it should be possible. PhStTransform is in hex.pm.
https://hex.pm/packages/phst_transform
I'm not an Elixir expert, but I know about transforming source code; see my bio.
If you have access to the AST as a data structure, you can always write procedural code to climb over it and hack at where you want something different. I assume if Elixir will give you the AST, it will give you access/modification procedures for working with it. This is compiler 101.
That's usually NOT pretty code to write or maintain. And, it may not be enough: you often need more than just the AST to do serious analysis and transformation. See my essay on Life After Parsingl. Think of this as compiler 102.
One the first stumbling blocks is regenerating text from the AST. Here is my SO discussion on how to prettyprint an AST, and why it is harder than it looks: http://stackoverflow.com/a/5834775/120163
(Sounds like Fred the Magic Wonder Dog didn't think what Elixir offered was enough and is inventing his own extensions to make this easier.).

Related Links

Macro that defines macro returning struct constant
Array of Expressions to an Array Definition
Code generation from restricted set of input
System of equations using metaprogramming
How to define a partial copy constructor metaprogramically in Julia?
How to interpolate into a Julia “for” expression?
Sending a keyword list to a macro and using bind_quoted
Runtime meta programming in ceylon
Is there a fast way of going from a symbol to a function call in Julia? [duplicate]
Programmatically alter Elixir Code
Elixir - How can I unquote an array of functions in my macro?
Nim reflect on type's field types at compile-time
Save variables to file at runtime
In Julia, is it possible to pass values for evaluation in an Expr object without using global variables?
Metaprogramming in Julia — Splice integer into variable name
What's the difference between `use` and `#before_compile`?

Categories

HOME
phpword
gridview
android-studio-2.2
themes
cublas
vxml
hpc
settings
google-admin-sdk
vert.x
nstableheaderview
g++
google-schemas
octave
reactive-programming
siddhi
mxgraph
ipmitool
selenium-ide
scrolltop
android-intent
coin3d
chargify
enterprise-miner
windows-xp
drive
squashfs
named-entity-recognition
mongoid6
exploit
windows-server-2003
data.stackexchange.com
syntax-highlighting
intersystems-cache
winexe
quantlib
comparable
twiml
corenlp-server
autodesk-designautomation
paragraph
quickfixj
lint
xcode7.3
odroid
railstutorial.org
css-position
xv6
skylink
branching-and-merging
ssrs-2014
signal-strength
mesosphere
gitlist
scalding
boxing
truezip
filenet
stax
iotivity
dotnetnuke-7
tooleap
firebase-security
omniauth-facebook
php-socket
query-by-example
hadoop-partitioning
aspen
relativelayout
sapi
sciruby
java-money
include-guards
toolkit
mod-proxy
zxspectrum
dot.js
xmltype
cosine-similarity
filesplitting
unix-socket
mutual-authentication
twitter-bootstrap-rails
sbcl
rfc5322
breakout
isqlquery
cocoalibspotify-2.0
node-blade
abstract-data-type
preload
sqlclr
fragmenttransaction
saleslogix
rmiregistry
paginator
agility.js
entitydatasource
pylucene
drawtobitmap
creole
cgbitmapcontextcreate
http-daemon
unattended-processing
commerceserver2007
sifr
build-environment
web-application-project
pnrp

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App