Skip to content

Instantly share code, notes, and snippets.

@teamon
Last active November 24, 2021 19:58
Embed
What would you like to do?
defmodule App do
use Thor
desc "List things"
def list do
IO.puts "listing"
end
desc "Install something"
def install(name) do
IO.puts "installing #{name}"
end
end
-compile(no_auto_import).
-file("thor.exs", 48).
-module('Elixir.App').
-export(['__info__'/1, help/0, install/1, list/0,
run/1]).
-spec({{'__info__', 1},
[{type, 48, 'fun',
[{type, 48, product,
[{type, 48, union,
[{atom, 48, attributes}, {atom, 48, compile},
{atom, 48, exports}, {atom, 48, functions},
{atom, 48, macros}, {atom, 48, md5}, {atom, 48, module},
{atom, 48, native_addresses}]}]},
{type, 48, union,
[{type, 48, atom, []},
{type, 48, list,
[{type, 48, union,
[{type, 48, tuple,
[{type, 48, atom, []}, {type, 48, any, []}]},
{type, 48, tuple,
[{type, 48, atom, []}, {type, 48, byte, []},
{type, 48, integer, []}]}]}]}]}]}]}).
'__info__'(functions) ->
[{help, 0}, {install, 1}, {list, 0}, {run, 1}];
'__info__'(macros) -> [];
'__info__'(info) ->
erlang:get_module_info('Elixir.App', info).
help() ->
lists:reverse('Elixir.Enum':reduce([{install,
<<"Install something">>},
{list, <<"List things">>}],
[],
fun ({_@3, _@4}, _@1) ->
['Elixir.IO':puts(<<case _@3 of
_@5
when
erlang:is_binary(_@5) ->
_@5;
_@6 ->
'Elixir.String.Chars':to_string(_@6)
end/binary,
" - ",
case _@4 of
_@7
when
erlang:is_binary(_@7) ->
_@7;
_@8 ->
'Elixir.String.Chars':to_string(_@8)
end/binary>>)
| _@1];
(_, _@1) -> _@1
end)).
install(name@1) ->
'Elixir.IO':puts(<<"installing ",
case name@1 of
_@1 when erlang:is_binary(_@1) -> _@1;
_@2 -> 'Elixir.String.Chars':to_string(_@2)
end/binary>>).
list() -> 'Elixir.IO':puts(<<"listing">>).
run([]) -> help();
run([_@1 | _@2]) ->
erlang:apply('Elixir.App',
erlang:binary_to_atom(_@1, utf8), _@2).
defmodule Thor do
defmacro __using__(_opts) do
quote do
import Thor.Builder, only: [desc: 1]
Module.register_attribute(__MODULE__, :desc, [])
Module.register_attribute(__MODULE__, :actions, accumulate: true)
@on_definition Thor.Builder
@before_compile Thor.Builder
end
end
defmodule Builder do
defmacro desc(text) do
quote do
@desc unquote(text)
end
end
def __on_definition__(env, :def, name, _args, _guards, _body) do
if desc = Module.get_attribute(env.module, :desc) do
Module.put_attribute(env.module, :actions, {name, desc})
Module.delete_attribute(env.module, :desc)
end
end
def __on_definition__(_, _, _, _, _, _) do
end
defmacro __before_compile__(_env) do
quote do
def run([]) do
help
end
def run([action | args]) do
apply(__MODULE__, String.to_atom(action), args)
end
def help do
for {action, desc} <- @actions do
IO.puts "#{action} - #{desc}"
end
end
end
end
end
end
class Thor
def self.inherited(base)
base.extend(ClassMethods)
end
def run(args)
if cmd = args.shift
send(cmd, *args)
else
help
end
end
def help
self.class.__actions.each do |action, desc|
puts "#{action} - #{desc}"
end
end
module ClassMethods
def desc(text)
@__desc = text
end
def method_added(method)
if @__desc
__actions << [method, @__desc]
@__desc = nil
end
end
def __actions
@__actions ||= []
end
def run(args)
new.run(args)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment