Skip to content

Commit

Permalink
Blueprint module generate complete
Browse files Browse the repository at this point in the history
Fix docs and tests
  • Loading branch information
alisinabh committed Jun 16, 2017
1 parent 25e1b12 commit a85b07a
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 34 deletions.
40 changes: 33 additions & 7 deletions lib/mix/tasks/from_blueprint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ defmodule Mix.Tasks.Prex.Gen.FromBlueprint do

use Mix.Task

@shortdoc "Create interface of API based on blueprint json"
@shortdoc "Create modules for API based on ApiBlueprint"

@bljson_filename ".prex.api.json"

def run([filename, api_name]) do
{current_dir, _} = System.cmd "pwd", []
Expand All @@ -20,32 +22,56 @@ defmodule Mix.Tasks.Prex.Gen.FromBlueprint do

if full_name |> String.downcase |> String.ends_with?(".apib") do
{data, _} = System.cmd("drafter", ["-t" ,"ast", "-f", "json", full_name])
File.rm "api.json"
File.write("api.json", data)
File.rm @bljson_filename
File.write(@bljson_filename, data)
else
System.cmd("cp", ["#{full_name}", "api.json"])
System.cmd("cp", ["#{full_name}", @bljson_filename])
end

file = Prex.AstFile.parse_file! "api.json"
file = Prex.AstFile.parse_file! @bljson_filename
groups = Prex.AstFile.get_resource_groups file
host = Prex.AstFile.get_host file

process_groups groups, api_name, host
:ok = process_groups groups, api_name, host

File.rm @bljson_filename
end

def run(_) do
IO.puts "mix prex.gen.from_blueprint [blueprint or json blueprint file] [a name for this api]"
IO.puts "mix prex.gen.from_blueprint [.apib or .json file] [api name]"
end

defp process_groups([gp | tail], api_name, base_url) do
{:ok, filename, code} = Prex.generate_module(api_name ,gp, base_url)
# File.open(filename, :write)

:ok = prepare_directory(filename)

File.touch filename
File.write filename, code

process_groups(tail, api_name, base_url)
end

defp process_groups([], _, _), do: :ok

defp prepare_directory(full_name) when is_binary(full_name) do
dirs = String.split(full_name, "/")
dirs = Enum.take(dirs, Enum.count(dirs) - 1)

prepare_directory(dirs, "")
end

defp prepare_directory([dir | tail], parent) do
new_path = Path.join(parent, dir)
if !File.exists?(dir) do
new_path |> File.mkdir!
end
prepare_directory(tail, new_path)
end

defp prepare_directory([], _) do
:ok
end

end
12 changes: 6 additions & 6 deletions lib/prex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,27 @@ defmodule Prex do
"""

import Prex.NameHelpers
import Prex.AstFile

@doc """
Generate elixir modules for a group
"""
@spec generate_module(String.t, Map.t, String.t) :: {:ok, String.t, String.t}
def generate_module(api_name, group, base_url) do
%{"name" => group_name, "description" => group_description, "resources" => resources} = group
actions_code = do_generate_module(base_url, group_name, group_description, resources, [])
actions_code = do_generate_module(resources, "")

{:ok,
"#{normalize_var_name(api_name)}__#{normalize_var_name(group_name)}.ex", # TODO fix folders
"lib/#{normalize_var_name(api_name)}/#{normalize_var_name(group_name)}.ex", # TODO fix folders
Prex.Templates.get_module(api_name, group_name, base_url, group_description, actions_code)}
end

defp do_generate_module(base_url, group_name, group_description, [resource | tail], acc) do
defp do_generate_module([resource | tail], acc) do
%{"name" => name, "uriTemplate" => uri, "parameters" => global_params, "actions" => actions} = resource

get_actions(uri, global_params, actions, "")
do_generate_module tail, acc <> " # #{name}\n\n" <> get_actions(uri, global_params, actions, "")
end

defp do_generate_module(_group_name, _group_description, [], acc), do: acc
defp do_generate_module([], acc), do: acc

defp get_actions(uri, global_params, [action | tail], acc) do
%{"name" => name, "description" => description, "method" => method, "parameters" => parameters} = action
Expand All @@ -35,4 +34,5 @@ defmodule Prex do
end

defp get_actions(_uri, _global_params, [], acc), do: acc

end
61 changes: 51 additions & 10 deletions lib/prex/name_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,66 @@ defmodule Prex.NameHelpers do
Naming helpers for Prex
"""

@doc false
@doc """
Normalizes a module name to use in elixir
## Examples
iex> Prex.NameHelpers.normalize_module_name " hello world"
"Helloworld"
"""
@spec normalize_module_name(String.t) :: String.t
def normalize_module_name(mod_name) do
mod_name = mod_name |> String.replace(" ", "")
IO.puts mod_name
mod_name = mod_name |> remove_schar |> String.replace(" ", "")
String.upcase(String.at(mod_name, 0)) <> String.slice(mod_name, 1, String.length(mod_name))
end

@doc false
@doc """
Normalizes function names for use in elixir
## Examples
iex> Prex.NameHelpers.normalize_func_name "(Get user info )"
"get_user_info"
"""
@spec normalize_func_name(String.t) :: String.t
def normalize_func_name(fun_name) do
fun_name |> String.downcase |> String.replace(" ", "_")
fun_name |> remove_schar |> String.trim |> String.downcase |> String.replace(" ", "_")
end

@doc false

@doc """
Converts an http method name to equivalant atom for HTTPoison to use
## Examples
iex> Prex.NameHelpers.normalize_http_method "GET"
":get"
iex> Prex.NameHelpers.normalize_http_method "POST "
":post"
"""
@spec normalize_http_method(String.t) :: String.t
def normalize_http_method(method) do
(":" <> method) |> String.downcase |> String.trim
":" <> (method |> remove_schar |> String.downcase |> String.trim |> String.replace(" ", ""))
end

@doc false
@doc """
Normalizes a variable name for use in elixir
## Examples
iex> Prex.NameHelpers.normalize_var_name "A bad var name "
"a_bad_var_name"
"""
@spec normalize_var_name(String.t) :: String.t
def normalize_var_name(var_name) do
var_name |> String.downcase |> String.replace(" ", "_")
var_name |> String.trim |> remove_schar |> String.replace(" ", "_") |> String.downcase
end

@doc """
Remove special chars form string
## Examples
iex> Prex.NameHelpers.remove_schar "s()72mca&q "
"s72mcaq "
"""
@spec remove_schar(String.t) :: String.t
def remove_schar(string), do: String.replace(string, ~r/[^0-9a-zA-Z ]/, "")

end
70 changes: 59 additions & 11 deletions lib/prex/templates.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@ defmodule Prex.Templates do

import Prex.NameHelpers

@doc """
Creates an elixir module code for an API group
## Parameters
- api_name: The name of the api. Used to determine module name.
- group_name: Name of api group
- base_url: Base url of current group. e.g. "http://example.com"
- docs: description of current module
- actions: group actions
"""
@spec get_module(String.t, String.t, String.t, String.t, Enum.t) :: String.t
def get_module(api_name, group_name, base_url, docs, actions) do
module_name = normalize_module_name(api_name) <> "." <> normalize_module_name(group_name)
"""
# Created by Prex
defmodule #{module_name} do
@moduledoc \"\"\"
#{docs}
#{docs |> String.replace("\n", "\n ")}
\"\"\"
@base_url \"#{base_url}\"
Expand All @@ -24,6 +35,7 @@ defmodule Prex.Templates do
"""
end

@spec get_module(String.t, String.t, String.t, [], String.t) :: String.t
def action_template(name, url, method, [], docs) do
action_name = normalize_func_name(name)
req_method = normalize_http_method method
Expand All @@ -37,50 +49,86 @@ defmodule Prex.Templates do
end
def #{action_name}! do
{:ok, result} = #{action_name}
{:ok, result} = #{action_name}()
result
end
"""
end

@doc """
Generates elixir code for an action without any arguments
## Parameters:
- name: Name of action
- url: Url of action
- method: Http method of action
- params: List of action parameters
- docs: Action documentation
"""
@spec get_module(String.t, String.t, String.t, Enum.t, String.t) :: String.t
def action_template(name, url, method, params, docs) do
action_name = normalize_func_name(name)
req_method = normalize_http_method method
{:ok, action_params, body} = get_action_params(params, "", "")
{:ok, action_params, recall_params, body, param_docs} = get_action_params(params, "", "", "", "")
"""
@doc \"\"\"
#{docs}
## Parameters
#{param_docs}
\"\"\"
def #{action_name}(#{action_params}) do
req_url = Path.join @base_url, \"#{url}\"
HTTPoison.request(#{req_method}, req_url, body: Poison.encode!(%{#{body}}), headers: ["Content-Type": "application/json"])
end
def #{action_name}!(#{action_params}) do
{:ok, result} = #{action_name}(#{action_params})
{:ok, result} = #{action_name}(#{recall_params})
result
end
"""
end

defp get_action_params([param | tail], param_acc, body_acc) do
defp get_action_params([param | tail], param_acc, recall_acc, body_acc, doc_acc) do
%{"name" => name, "description" => description, "required" => required, "default" => default} = param

var_name = normalize_var_name(name)

new_param_acc = param_acc <> var_name <> ","
new_param_acc = param_acc <> var_name

new_param_acc =
case {required, default} do
{true, nil} ->
new_param_acc
{true, default_val} ->
new_param_acc <> " \\\\ \"#{default_val}\""
{false, nil} ->
new_param_acc <> " \\\\ nil"
{false, ""} ->
new_param_acc <> " \\\\ nil"
{false, default_val} ->
new_param_acc <> " \\\\ \"#{default_val}\""
end

new_param_acc = new_param_acc <> ","

new_recall_acc = recall_acc <> var_name <> ","

new_body_acc = body_acc <> " \"#{name}\" => #{var_name},"

get_action_params(tail, new_param_acc, new_body_acc)
new_doc_acc = doc_acc <> "\n- #{var_name}: #{description}"

get_action_params(tail, new_param_acc, new_recall_acc, new_body_acc, new_doc_acc)
end

defp get_action_params([], param_acc, body_acc) do
param = param_acc |> String.slice(0, String.length(param_acc) - 1)
defp get_action_params([], param_acc, recall_acc, body_acc, doc_acc) do
param = param_acc |> String.slice(0, String.length(param_acc) - 1) |> String.replace(",", ", ")
recall = recall_acc |> String.slice(0, String.length(recall_acc) - 1) |> String.replace(",", ", ")
body = body_acc |> String.slice(0, String.length(body_acc) - 1)

{:ok, param, body}
doc = " " <> (doc_acc |> String.slice(1, String.length(doc_acc)) |> String.replace("\n", "\n "))
{:ok, param, recall, body, doc}
end

end
1 change: 1 addition & 0 deletions test/prex_test.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule PrexTest do
use ExUnit.Case
doctest Prex
doctest Prex.NameHelpers

test "the truth" do
assert 1 + 1 == 2
Expand Down

0 comments on commit a85b07a

Please sign in to comment.