zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

registry.ex (7623B)


      1 defmodule Makeup.Registry do
      2   @moduledoc """
      3   A registry that allows users to dynamically register new makeup lexers.
      4 
      5   Lexers should register themselves on application start.
      6   That way, you can add support for new programming languages by depending on the relevant lexers.
      7   This is useful for projects such as ExDoc, which might contain code
      8   in a number of different programming languages.
      9   """
     10 
     11   @name_registry_key :lexer_name_registry
     12 
     13   @extension_registry_key :lexer_extension_registry
     14 
     15   # --------------------------------------------------------------------------
     16   # Public API
     17   # --------------------------------------------------------------------------
     18 
     19   @doc """
     20   Gets the list of supported language names.
     21   """
     22   def supported_language_names() do
     23     Map.keys(get_name_registry())
     24   end
     25 
     26   @doc """
     27   Gets the list of supported language extensions.
     28   """
     29   def supported_file_extensions() do
     30     Map.keys(get_extension_registry())
     31   end
     32 
     33   @doc """
     34   Adds a new lexer to Makeup's registry under the given `name`.
     35 
     36   This function expects a language name (e.g. `"elixir"`) and a pair containing
     37   a `lexer` and a list of `options`.
     38 
     39   You might want to use the `Makeup.Registry.register_lexer/2` function instead.
     40 
     41   ## Examples
     42 
     43       alias Makeup.Lexers.ElixirLexer
     44       alias Makeup.Registry
     45 
     46       Registry.register_lexer_with_name("elixir", {ElixirLexer, []})
     47       Registry.register_lexer_with_name("iex", {ElixirLexer, []})
     48   """
     49   def register_lexer_with_name(name, {lexer, options}) when is_binary(name) do
     50     old_registry = get_name_registry()
     51     updated_registry = Map.put(old_registry, name, {lexer, options})
     52     put_name_registry(updated_registry)
     53   end
     54 
     55   @doc """
     56   Adds a new lexer to Makeup's registry under the given `extension`.
     57 
     58   This function expects a file extension (e.g. `"ex"`) and a pair containing
     59   a `lexer` and a list of `options`.
     60 
     61   You might want to use the `Makeup.Registry.register_lexer/2` function instead.
     62 
     63   ## Examples
     64 
     65       alias Makeup.Lexers.ElixirLexer
     66       alias Makeup.Registry
     67 
     68       Registry.register_lexer_with_extension("ex"), {ElixirLexer, []})
     69       Registry.register_lexer_with_extension("exs"), {ElixirLexer, []})
     70   """
     71   def register_lexer_with_extension(name, {lexer, options}) when is_binary(name) do
     72     old_registry = get_extension_registry()
     73     updated_registry = Map.put(old_registry, name, {lexer, options})
     74     put_extension_registry(updated_registry)
     75   end
     76 
     77   @doc """
     78   Add a new lexer to Makeup's registry under the given names and extensions.
     79 
     80   Expects a lexer `lexer` and a number of options:
     81 
     82     * `:options` (default: `[]`) - the lexer options.
     83       If your lexer doesn't take any options, you'll want the default value of `[]`.
     84 
     85     * `:names` (default: `[]`) - a list of strings with the language names for the lexer.
     86       Language names are strings, not atoms.
     87       Even if there is only one valid name, you must supply a list with that name.
     88       To avoid filling the registry unnecessarily, you should normalize your language names
     89       to lowercase strings.
     90       If the caller wants to support upper case language names for some reason,
     91       they can normalize the language names themselves.
     92 
     93     * `:extensions` (default: `[]`) - the list of file extensions for the languages supported by the lexer.
     94       For example, the elixir lexer should support the `"ex"` and `"exs"` file extensions.
     95       The extensions should not include the dot.
     96       That is, you should register `"ex"` and not `".ex"`.
     97       Even if there is only a supported extension, you must supply a list.
     98 
     99   ## Example
    100 
    101       alias Makeup.Registry
    102       alias Makeup.Lexers.ElixirLexer
    103       # The `:options` key is not required
    104       Registry.register_lexer(ElixirLexer, names: ["elixir", "iex"], extensions: ["ex", "exs"])
    105 
    106   """
    107   def register_lexer(lexer, opts) do
    108     options = Keyword.get(opts, :options, [])
    109     names = Keyword.get(opts, :names, [])
    110     extensions = Keyword.get(opts, :extensions, [])
    111     # Associate the lexer with the names
    112     for name <- names, do: register_lexer_with_name(name, {lexer, options})
    113     # Associate the lexer with the extensions
    114     for extension <- extensions, do: register_lexer_with_extension(extension, {lexer, options})
    115   end
    116 
    117   @doc """
    118   Fetches the lexer from Makeup's registry with the given `name`.
    119 
    120   Returns either `{:ok, {lexer, options}}` or `:error`.
    121   This behaviour is based on `Map.fetch/2`.
    122   """
    123   def fetch_lexer_by_name(name) do
    124     Map.fetch(get_name_registry(), name)
    125   end
    126 
    127   @doc """
    128   Fetches the lexer from Makeup's registry with the given `name`.
    129 
    130   Returns either `{lexer, options}` or raises a `KeyError`.
    131   This behaviour is based on `Map.fetch!/2`.
    132   """
    133   def fetch_lexer_by_name!(name) do
    134     Map.fetch!(get_name_registry(), name)
    135   end
    136 
    137   @doc """
    138   Gets the lexer from Makeup's registry with the given `name`.
    139 
    140   Returns either `{lexer, options}` or the `default` value
    141   (which by default is `nil`).
    142   This behaviour is based on `Map.get/3`.
    143   """
    144   def get_lexer_by_name(name, default \\ nil) do
    145     Map.get(get_name_registry(), name, default)
    146   end
    147 
    148   @doc """
    149   Fetches a lexer from Makeup's registry with the given file `extension`.
    150 
    151   Returns either `{:ok, {lexer, options}}` or `:error`.
    152   This behaviour is based on `Map.fetch/2`.
    153   """
    154   def fetch_lexer_by_extension(name) do
    155     Map.fetch(get_extension_registry(), name)
    156   end
    157 
    158   @doc """
    159   Fetches the lexer from Makeup's registry with the given file `extension`.
    160 
    161   Returns either `{:ok, {lexer, options}}` or raises a `KeyError`.
    162   This behaviour is based on `Map.fetch/2`.
    163   """
    164   def fetch_lexer_by_extension!(name) do
    165     Map.fetch!(get_extension_registry(), name)
    166   end
    167 
    168   @doc """
    169   Gets the lexer from Makeup's registry with the given file `extension`.
    170 
    171   Returns either `{lexer, options}` or the `default` value
    172   (which by default is `nil`).
    173   This behaviour is based on `Map.get/3`.
    174   """
    175   def get_lexer_by_extension(name, default \\ nil) do
    176     Map.get(get_extension_registry(), name, default)
    177   end
    178 
    179   # ---------------------------------------------------------------------------
    180   # Functions not meant to be used outside Makeup
    181   # ---------------------------------------------------------------------------
    182   # This functions are meant to be run on application startup
    183   # or to be used as helpers in Makeup's internal tests.
    184   # They are not meant to be invoked by users of Makeup
    185 
    186   @doc false
    187   def create_name_registry() do
    188     Application.put_env(:makeup, @name_registry_key, %{})
    189   end
    190 
    191   @doc false
    192   def create_extension_registry() do
    193     Application.put_env(:makeup, @extension_registry_key, %{})
    194   end
    195 
    196   # The `clean_*_registry` are actually the same as the `create_*_registry`,
    197   # but that's because of implementation details, so it makes sense to have
    198   # separate groups of functions
    199 
    200   @doc false
    201   def clean_name_registry() do
    202     put_name_registry(%{})
    203   end
    204 
    205   @doc false
    206   def clean_extension_registry() do
    207     put_extension_registry(%{})
    208   end
    209 
    210   # ----------------------------------------------------------------------------
    211   # Private helper functions
    212   # ----------------------------------------------------------------------------
    213 
    214   defp get_name_registry() do
    215     Application.get_env(:makeup, @name_registry_key)
    216   end
    217 
    218   defp put_name_registry(registry) do
    219     Application.put_env(:makeup, @name_registry_key, registry)
    220   end
    221 
    222   defp get_extension_registry() do
    223     Application.get_env(:makeup, @extension_registry_key)
    224   end
    225 
    226   defp put_extension_registry(registry) do
    227     Application.put_env(:makeup, @extension_registry_key, registry)
    228   end
    229 end