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

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`?
How to define functions based on attribute to elixir?
Remove a const qualifier from a variable in D

Categories

HOME
notepad++
phantom-dsl
adal
forms
fpga
flex
rsa
socket.io
solver
shiro
error-handling
r-googlesheets
yandex
tivoli
azure-container-service
barcode
fabric.io
watson-conversation
google-form
radgridview
shared-libraries
flash-player
mathprog
red5
wolframalpha
hta
exit
exploit
tosca
jquery-callback
xunit
moses
has-and-belongs-to-many
android-maps
firebase-analytics
openmdao
mql
scrollview
mockjax
simplecv
twos-complement
keras-layer
pop3
sharding
imx6
sharp-snmp
photos
x++
servermanager
term
facebook-pixel
tinymce-3
mongotemplate
video-conferencing
azure-cli
compiler-design
er-diagram
gameplay-kit
centrifuge
cifilter
eigenvector
xdoclet
android-wake-lock
http-status-code-401
tracker-enabled-dbcontext
uiactionsheet
libav
jaunt-api
pypiserver
google-books
video-player
opserver
atoi
liquid-layout
jsvc
ansi
shopizer
cakephp-2.7
umlgraph
gamekit
code-documentation
exceldatareader
ejb-2.x
nodelist
android-vibration
iso-prolog
insight.database
named-parameters
ss7
kissfft
renderer
extjs2
light
kaleidoscope
booksleeve
redis-py
patricia-trie
wcf-configuration
dajaxice
subproject
usertype
saxparseexception
jqote
drawtobitmap
massive
diagrams
resharper-6.0
globals
object-database
asynchronous-wcf-call
entitykey

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