Skip to content

Instantly share code, notes, and snippets.

@teamon
Last active November 24, 2021 19:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save teamon/6b8a6813dc941d69355e90cf1df734c0 to your computer and use it in GitHub Desktop.
Save teamon/6b8a6813dc941d69355e90cf1df734c0 to your computer and use it in GitHub Desktop.
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