Skip to content

Commit

Permalink
feat: Implement 'make:module' command in Rosemary
Browse files Browse the repository at this point in the history
  • Loading branch information
drorganvidez committed Mar 24, 2024
1 parent bc6abbd commit a922740
Show file tree
Hide file tree
Showing 17 changed files with 168 additions and 5 deletions.
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,39 @@ rosemary update
Note: it is the responsibility of the developer to check that the update of the dependencies has not broken any
functionality and each dependency maintains backwards compatibility. Use the script with care!

### Viewing Environment Variables
### Extending the Project with New Modules

To view the current `.env` file settings, use:
To quickly generate a new module within the project, including necessary boilerplate files
like `__init__.py`, `routes.py`, `models.py`, `repositories.py`, `services.py`, `forms.py`,
and a basic `index.html` template, you can use the `rosemary` CLI tool's `make:module`
command. This command will create a new blueprint structure ready for development.

To create a new module, run the following command from the root of the project:

```
rosemary make:module <module_name>
```

Replace `<module_name>` with the desired name of your module. For example, to create a
module named "zenodo", you would run:

```
rosemary env
rosemary make:module zenodo
```


This command creates a new directory under `app/blueprints/` with the name of your module and sets up the initial files and directories needed to get started, including a dedicated `templates` directory for your module's templates.

**Note:** If the module already exists, `rosemary` will simply notify you and not overwrite any existing files.

This feature is designed to streamline the development process, making it easy to add new features to the project.


### Available Commands

- `rosemary update`: Updates all project dependencies and the `requirements.txt` file.
- `rosemary info`: Displays information about the Rosemary CLI, including version and author.
- `rosemary make:module <module_name>`: Generates a new module with the specified name.
- `rosemary env`: Displays the current environment variables from the `.env` file.

## Deploy in production (Docker Compose)
Expand Down
3 changes: 3 additions & 0 deletions app/blueprints/zenodo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from flask import Blueprint

zenodo_bp = Blueprint('zenodo', __name__, template_folder='templates')
6 changes: 6 additions & 0 deletions app/blueprints/zenodo/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from flask_wtf import FlaskForm
from wtforms import SubmitField


class ZenodoForm(FlaskForm):
submit = SubmitField('Save zenodo')
5 changes: 5 additions & 0 deletions app/blueprints/zenodo/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from app import db


class Zenodo(db.Model):
id = db.Column(db.Integer, primary_key=True)
7 changes: 7 additions & 0 deletions app/blueprints/zenodo/repositories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from app.blueprints.zenodo.models import Zenodo
from app.repositories.BaseRepository import BaseRepository


class ZenodoRepository(BaseRepository):
def __init__(self):
super().__init__(Zenodo)
7 changes: 7 additions & 0 deletions app/blueprints/zenodo/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from flask import render_template
from app.blueprints.zenodo import zenodo_bp


@zenodo_bp.route('/zenodo', methods=['GET'])
def index():
return render_template('zenodo/index.html')
7 changes: 7 additions & 0 deletions app/blueprints/zenodo/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from app.blueprints.zenodo.repositories import ZenodoRepository
from app.services.BaseService import BaseService


class Zenodo(BaseService):
def __init__(self):
super().__init__(ZenodoRepository())
7 changes: 7 additions & 0 deletions app/blueprints/zenodo/templates/zenodo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% extends "base_template.html" %}

{% block title %}View zenodo{% endblock %}

{% block content %}

{% endblock %}
4 changes: 2 additions & 2 deletions rosemary/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import click
from rosemary.commands.update import update
from rosemary.commands.info import info
from rosemary.commands.env import env
from rosemary.commands.make_module import make_module


@click.group()
Expand All @@ -13,7 +13,7 @@ def cli():

cli.add_command(update)
cli.add_command(info)
cli.add_command(env)
cli.add_command(make_module)

if __name__ == '__main__':
cli()
57 changes: 57 additions & 0 deletions rosemary/commands/make_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import click
from jinja2 import Environment, FileSystemLoader, select_autoescape
import os


def pascalcase(s):
"""Converts string to PascalCase."""
return ''.join(word.capitalize() for word in s.split('_'))


def setup_jinja_env():
"""Configures and returns a Jinja environment."""
env = Environment(
loader=FileSystemLoader(searchpath="./rosemary/templates"),
autoescape=select_autoescape(['html', 'xml', 'j2'])
)
env.filters['pascalcase'] = pascalcase
return env


def render_and_write_file(env, template_name, filename, context):
"""Renders a template and writes it to a specified file."""
template = env.get_template(template_name)
content = template.render(context) + "\n"
with open(filename, 'w') as f:
f.write(content)


@click.command('make:module', help="Creates a new module with a given name.")
@click.argument('name')
def make_module(name):
blueprint_path = f'app/blueprints/{name}'

if os.path.exists(blueprint_path):
click.echo(f"The module '{name}' already exists.")
return

env = setup_jinja_env()

files_and_templates = {
'__init__.py': 'blueprint_init.py.j2',
'routes.py': 'blueprint_routes.py.j2',
'models.py': 'blueprint_models.py.j2',
'repositories.py': 'blueprint_repositories.py.j2',
'services.py': 'blueprint_services.py.j2',
'forms.py': 'blueprint_forms.py.j2',
os.path.join('templates', name, 'index.html'): 'blueprint_templates_index.html.j2'
}

# Create necessary directories
os.makedirs(os.path.join(blueprint_path, 'templates', name), exist_ok=True)

# Render and write files
for filename, template_name in files_and_templates.items():
render_and_write_file(env, template_name, os.path.join(blueprint_path, filename), {'blueprint_name': name})

click.echo(f"Module '{name}' created successfully.")
6 changes: 6 additions & 0 deletions rosemary/templates/blueprint_forms.py.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from flask_wtf import FlaskForm
from wtforms import SubmitField


class {{ blueprint_name | pascalcase }}Form(FlaskForm):
submit = SubmitField('Save {{ blueprint_name }}')
3 changes: 3 additions & 0 deletions rosemary/templates/blueprint_init.py.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from flask import Blueprint

{{ blueprint_name }}_bp = Blueprint('{{ blueprint_name }}', __name__, template_folder='templates')
5 changes: 5 additions & 0 deletions rosemary/templates/blueprint_models.py.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from app import db


class {{ blueprint_name | pascalcase }}(db.Model):
id = db.Column(db.Integer, primary_key=True)
7 changes: 7 additions & 0 deletions rosemary/templates/blueprint_repositories.py.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from app.blueprints.{{ blueprint_name }}.models import {{ blueprint_name | pascalcase }}
from app.repositories.BaseRepository import BaseRepository


class {{ blueprint_name | pascalcase }}Repository(BaseRepository):
def __init__(self):
super().__init__({{ blueprint_name | pascalcase }})
7 changes: 7 additions & 0 deletions rosemary/templates/blueprint_routes.py.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from flask import render_template
from app.blueprints.{{ blueprint_name }} import {{ blueprint_name }}_bp


@{{ blueprint_name }}_bp.route('/{{ blueprint_name }}', methods=['GET'])
def index():
return render_template('{{ blueprint_name }}/index.html')
7 changes: 7 additions & 0 deletions rosemary/templates/blueprint_services.py.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from app.blueprints.{{ blueprint_name }}.repositories import {{ blueprint_name | pascalcase }}Repository
from app.services.BaseService import BaseService


class {{ blueprint_name | pascalcase }}(BaseService):
def __init__(self):
super().__init__({{ blueprint_name | pascalcase }}Repository())
7 changes: 7 additions & 0 deletions rosemary/templates/blueprint_templates_index.html.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% raw %}{%{% endraw %} extends "base_template.html" {% raw %}%}{% endraw %}

{% raw %}{%{% endraw %} block title {% raw %}%}{% endraw %}View {{ blueprint_name }}{% raw %}{%{% endraw %} endblock {% raw %}%}{% endraw %}

{% raw %}{%{% endraw %} block content {% raw %}%}{% endraw %}

{% raw %}{%{% endraw %} endblock {% raw %}%}{% endraw %}

0 comments on commit a922740

Please sign in to comment.