ucbi / uniform

Write less boilerplate and reuse more code in your portfolio of Elixir apps
https://hex.pm/packages/uniform
Apache License 2.0
33 stars 1 forks source link

DSL for MyApp.Eject.Project #4

Closed paulstatezny closed 2 years ago

paulstatezny commented 2 years ago

Instead of having a modify function where you have to return a list of tuples, we could have macros.

We could make you specify a Modify module in config, and then do something like this:

modify :tests, ~r/^test\/.+_(test).exs/
modify :app_js, "assets/js/app.js"

The atom, e.g. :tests would map to a function in your Modify module.

Alternative for this might be:

@modify ~r/^test\/.+_(test).exs/
def modify_tests(file_contents, app) do
  String.replace(
    file_contents,
    "foo",
    "bar"
  )
end

Instead of defining a lib_deps function, we could do something like:

lib :docusign, mix_deps: [:norm, :stream_data, :faker]

lib :my_app_web,
  always: true,
  only: [
    "lib/my_app_web/endpoint.ex",
    "lib/my_app_web/router.ex",
    ...
  ]

lib :my_data_source,
  lib_deps: [:my_sso_provider],
  associated_files: Path.wildcard("priv/my_repo/**", match_dot: true)

Similarly, for mix deps:

mix :norm
mix :livebook

mix :absinthe, deps: [:absinthe_plug, :dataloader]

The different types of things you can return in base_files could be their own macros.

dir "assets"
template "config/runtime.exs"
file "lib/my_app_web.ex"
binary "bin/an_executable", chmod: 0o555

For the ejected_app option from the options/1 callback, we could have a macro that takes the same options as lib:

ejectable app do
  except: ["lib/#{app.name.snake}/router.ex"],
  lib_directory: fn path ->
    # ...
  end
end

(Unrelated: should we rename the fields in app.name to something less "jargon-ey"? name.underscore instead of name.snake, etc.)


Note in the above code snippet the syntax where you "bind" the app to a variable. If that's possible, we could make that option available in other callbacks where we currently reference the app. For example:

file app do
  if depends_on?(app, :lib, :my_lib) do
    "test/support/fixtures/some_fixture.ex"
  end
end
paulstatezny commented 2 years ago

This might also be a good opportunity to revisit the "rules" for specifying mix/lib deps.

Right now, unlisted mix deps are always included and unlisted lib deps are never included. If you try to reference an unlisted dep it errors.

But it may be smoother and more intuitive if it automatically detects both kinds of deps. And you only need to specify them if you want to attach options.

paulstatezny commented 2 years ago

Which would be a better API for specifying which mix/lib dependencies are always ejected?

:always option

mix :norm, always: true
mix :mint
mix :phoenix, always: true

lib :my_ui_components, always: true
lib :my_data_source
lib :my_auth_library, always: true

Pros:

Or, always macro

always do
  mix :norm
  mix :phoenix

  lib :my_ui_components
  lib :my_auth_library
end

mix :mint
lib :my_data_source

Pros:

*Counterpoint: there may still be transitive deps that are always included but outside the always block, but that's not a problem unique to this solution.

paulstatezny commented 2 years ago

Done in #11