ejpcmac / typed_struct

An Elixir library for defining structs with a type without writing boilerplate code.
MIT License
732 stars 36 forks source link

Add a plugin system #9

Closed ejpcmac closed 4 years ago

ejpcmac commented 5 years ago

Steps

Rationale

Structs are used to represent many things in Elixir. Other libraries sometimes provide their own macros to define special functions alongside the struct. While integrating them with TypedStruct could sometimes be handy, there are two main issues:

  1. there is potentially a large number of libraries to integrate and maintain compatibility with,
  2. it would add code to TypedStruct that would be use by only a restricted number of projects.

There are already features request for Ecto (#7) and lens libraries (#8). More could come, so I think a plugin system would be a better solution. While I do not see currently how it would fit for the Ecto case, simpler cases like defining special functions from the struct fields could be handled by a function:

defmodule MyStruct do
  use TypedStruct

  # This would contain the define_lenses/? function.
  # Its parameters and return type are yet to define.
  import LensPlugin

  typedstruct do
    plugin :define_lenses

    field :name, String.t()
    field :age, integer(), some: :option
  end
end

Plugin functions would be called after the fields have been processed, with any option like some: :option made available to it. The complete API is to define, but here is a first idea. It could be interesting to provide some helpers for users to define their own top-level macros to replace typedstruct or extending it. Integration with Ecto could be explored in such a way.

API definition

In its PR #12, @uberbrodt defines the plugin API as a behaviour. This seems to be a good start.

Plugin definition

A TypedStruct plugin is a module that implements the TypedStruct.Plugin behaviour. This behaviour is made of several callbacks, all optional to let some flexibility to the user:

Plugin usage

defmodule MyStruct do
  use TypedStruct

  typedstruct do
    plugin FirstPlugin
    plugin WithOptions, some: :option, another: "option"

    field :name, String.t()
    field :age, integer(), some: :option
  end
end

Options passed to the plugins are passed to the callbacks. The field/4 callbacks gets both the field-specific options and the plugin general option in its opts keyword.

uberbrodt commented 5 years ago

I'm nearing v1.0 on my project that uses the provisional typed_struct plugin system. I thought it might be helpful to see how I use it, while you're writing the official plugin system: https://github.com/uberbrodt/ex_constructor

ejpcmac commented 5 years ago

Hi Chris,

As stated in this comment, I am near to push the final API with a documentation in the develop branch, at first without the tests so you can integrate it.

I’ve been on vacation these past 10 days and I’m currently quite busy both in my professional and personal life, so I can work on it only from time to time. I’ll try to allocate some time on the docs this week to be able to push the code as soon as possible.

ejpcmac commented 5 years ago

I’ve just pushed 9b804d0b6c72d399f924edfd9805f2a76993ae12 which contains the code for the pre-final version of the plugin API. It should be pretty stable now, except if some flaw is found.

I’ve removed the tests since they don’t match anymore, and there is currently no documentation.

@uberbrodt By reading the code, you should be able to adapt your plugin fairly easily. The main difference about the field/3 callback is that it must return a quoted expression. It’s a function, but think about it like a macro that can inject additional code on each call of the TypedStruct.field/2,3 macro. Provided that I needed to call dynamically this callback on each field for each plugin, I couldn’t use a “real” macro and learned about Module.eval_quoted/2 which did the trick.

avitex commented 4 years ago

Just a friendly bump. Any ETA on this? :)

ejpcmac commented 4 years ago

@avitex I’m currently hard-working to free some time to get back on it soon.

Between August and November, I’ve been busy preparing my trip to Kerguelen Islands. In November I’ve been able to work a tiny bit on the documentation while at sea on the Marion Dufresne, but since my arrival in Kerguelen I’ve spent nearly all my spare time on writing about my experience there—I quite expected that, but not to that point.

My ETA on getting back to software development projects is around April 15-20th. TypedStruct 0.2.0 is number 1 on my list.

avitex commented 4 years ago

@ejpcmac Thanks for the speedy reply. Life just has a habit of rearranging priorities all the time. Stay safe out there!

ejpcmac commented 4 years ago

Life just has a habit of rearranging priorities all the time.

Well said @avitex! Since I’m a bit carving software development—I’m doing mostly sysadim here—be sure it is currently rising on my general priority list. It will be good to ship a new version and start working on new projects :)

ejpcmac commented 4 years ago

Hello all! I have some good news: I’m back on it starting today! I won’t be able to be 100% on it in my spare time so don’t expect something in two days, but I hope to release TypedStruct 0.2.0 around mid-May.

avitex commented 4 years ago

Awesome news :)

ejpcmac commented 4 years ago

I’ve just published the documentation on develop if you want to give it a try.

avitex commented 4 years ago

Will have a look today, thanks :)

ejpcmac commented 4 years ago

Quick ETA update : I’ve been busy again the past two weeks, not being able to work on TypedStruct at all. I’m on the field without my computer next week, but I have managed to free my schedule enough to start working on TypedStruct back on Monday 25th. It should be OK before mid-June then.