Sei sulla pagina 1di 21

Uma camada para modelagem de controladores no

HyperDE

Projeto final de programação

Mauricio Henrique de Souza Bomfim


Orientador: Daniel Schwabe
{mbomfim, dschwabe}@inf.puc-rio.br

Departamento de Informática – PUC-Rio


Rio de Janeiro, Brasil, dezembro de 2009

Resumo
O HyperDE é um ambiente para desenvolvimento de aplicações hipermídia na que não possui uma
camada para a definição do tratamento das requisições feitas pelos usuários à aplicação construída. A
ausência desta camada é percebida como falta de flexibilidade na construção das aplicações. O
problema é mais evidente quando o desenvolvedor precisa construir regras para controle de acesso à
aplicação ou criar o backend para o tratamento de dados enviados por formulários personalizados. O
objetivo deste projeto é adicionar uma camada para a definição de controles (a componente C da
arquitetura MVC) no HyperDE.

Sumário
1.Especificação do programa.................................................................................................................... 3
1.1.Objetivo.......................................................................................................................................... 3
1.2.Mini-acompanhamento da execução.............................................................................................. 3
1.3.Requisitos....................................................................................................................................... 4
1.4.Diagrama de Casos de Uso.............................................................................................................4
2.Projeto modular do programa................................................................................................................ 5
2.1.Critérios de projeto utilizados........................................................................................................ 5
2.2.Organização do programa...............................................................................................................6
3.Código fonte...........................................................................................................................................8
4.Testes automatizados............................................................................................................................16
4.1.Testes............................................................................................................................................ 16
4.2.Logs de testes............................................................................................................................... 18
5.Guia do usuário.................................................................................................................................... 20
5.1.Instalação......................................................................................................................................20
5.2.Usando controladores................................................................................................................... 20
a)Criando um controlador..............................................................................................................21
b)Criando uma ação.......................................................................................................................24
c)Observações................................................................................................................................25
1. Especificação do programa

1.1. Objetivo

O HyperDE é a combinação de um framework no padrão Model-View-Controller e um ambiente de


desenvolvimento visual para a construção de protótipos de aplicações hipermídia, modeladas através
dos métodos OOHDM ou SHDM [Nunes, D. 2005].
Embora seja descrito como um framework MVC, o HyperDE não possui uma camada para a
modelagem do comportamento em relação ao processamento e resposta aos eventos externos a
aplicação, geralmente gerados pelos usuários, papel do componente controlador do padrão de
arquitetura MVC.
A ausência desta camada é percebida como falta de flexibilidade na construção das aplicações. O
problema é mais evidente quando o desenvolvedor precisa construir regras para controle de acesso à
aplicação ou criar o backend para o tratamento de dados enviados por formulários personalizados.
O objetivo deste projeto é adicionar ao HyperDE uma camada que permita ao desenvolvedor modelar
classes de controladores que possam ser instanciadas em tempo de execução pelas aplicações
construídas em seu ambiente e assim atender a uma demanda dos desenvolvedores por uma maior
flexibilidade na construção de aplicações neste ambiente.

1.2. Mini-acompanhamento da execução.

Execução das tarefas


Tarefas Estatística de Tempo Esforço por Tarefa
Pesquisar sobre o ambiente Ruby on 10 dias Baixo
Rails
Analisar a implementação corrente do 6 dias Baixo
HyperDE
Realizar testes de prova de conceito 4 dias Médio
sobre o ambiente corrente
Análise de requisitos 2 dias Baixo
Especificar a arquitetura de 2 dias Baixo
implementação
Implementar modelo de controladores 10 dias Médio
Implementar modelo de ações 5 dias Médio
Implementar controladores de apoio 4 dias Médio
Implementar interpretador do modelo de 20 dias Alto
controladores em tempo de execução
Implementar testes automatizados 4 dias Médio
Consolidar documentação final 5 dias Baixo
1.3. Requisitos
A implementação da camada de controladores do HyperDE deve atender aos seguintes requisitos:
1. Permitir que o usuário modele classes de controladores através de uma interface gráfica.
1.1. Oferecer uma interface CRUD para as classes de controladores com hierarquia de classes.
1.2. Oferecer uma interface CRUD para as ações de cada controlador.
2. Implementar e instanciar em tempo de execução o código dos controladores modelados pelos
usuários, de forma que a aplicação reflita o comportamento definido por estes controladores.
2.1. Gerar os códigos das definições das classes de controladores com seus atributos e métodos
na linguagem Ruby.
2.2. Instanciar as classes de controladores.
2.3. Prover rotas para resposta às requisições http que acionem as ações das classes de
controladores.

1.4. Diagrama de Casos de Uso


Os casos de uso desse projeto devem considerar duas fronteiras. Uma para o meta-ambiente de
desenvolvimento do HyperDE, onde o desenvolvedor da aplicação modela os controladores e as suas
ações, e outra fronteira para a própria aplicação construída com o HyperDE. Desta maneira, definimos
dois usuários: o desenvolvedor da aplicação e o usuário da aplicação construída com o HyperDE.
2. Projeto modular do programa

2.1. Critérios de projeto utilizados


O HyperDE foi construído sobre o framework Ruby on Rails.

O Ruby on Rails é um framework de desenvolvimento web escrito na linguagem Ruby. Ele é designado
para tornar a programação de aplicações web mais fácil, fazendo várias suposições sobre o que cada
desenvolvedor precisa para começar. Ele permite que você escreva menos código enquanto faz mais
que muitas outras linguagens e frameworks.

Uma vez que o projeto aqui apresentado consistiu em adicionar uma nova funcionalidade ao HyperDE,
sua implementação utilizou o mesmo framework e desta maneira se beneficiou de seguir os mesmos
critérios de projeto e princípios de um projeto desenvolvido com o Ruby on Rails, alguns deles
herdados do uso do padrão MVC, entre os quais podemos destacar:

• Isolamento entre a lógica de negócios e a interface de usuário.


• Uso da arquitetura REST – organizar a aplicação web em torno de recursos e verbos HTTP.
• DRY – “Don’t Repeat Yourself” – evitar escrever o mesmo código várias vezes.
• Convenção ao invés de configuração.

2.2. Organização do programa.


Uma aplicação construída com o HyperDE é, assim como o próprio, uma aplicação Ruby on
Rails. Logo, esta aplicação segue a mesma arquitetura MVC do seu framework base.
Segue uma descrição de cada componente da arquitetura MVC do Ruby on Rails, retirada do
site railsguides.org.
Modelos: Um modelo representa a informação (dados) da aplicação e as regras para manipular
estes dados. No caso do Rails, modelos são usados primariamente para gerenciar as regras de interação
com uma tabela correspondente no banco de dados. Na maioria dos casos, uma tabela de seu banco de
dados corresponderá a um modelo em sua aplicação. A maior parte da lógica de negócio de sua
aplicação estará concentrado nos modelos.
Views (Visões): Views representam a interface de usuário na sua aplicação. No Rails, as views
são freqüentemente arquivos HTML com código Ruby embutido que efetua tarefas relacionadas
somente com a apresentação dos dados. As views gerenciam o trabalho de fornecer dados para o
navegador web ou outro acessório que é usado para enviar requisições à sua aplicação.
Controladores: Controladores fornecem a “cola” entre modelos e views. No Rails,
controladores são responsáveis por processar as requisições que chegam do navegador web,
interrogando os modelos pelos dados, e passando os dados para as views fazerem a apresentação.

Nosso objetivo é permitir que o desenvolvedor acrescente novos controladores às suas


aplicações construídas com o HyperDE através do próprio meta-ambiente. Assim, oferecemos um
ambiente para a modelagem desses controladores que serão instanciados em tempo de execução da
aplicação em controladores Rails.

A camada de modelagem de controladores foi implementada como um conjunto de classes de


modelo e uma classe de controlador do Rails, além dos templates para a interface gráfica.

As classes de modelo são responsáveis pela persistência da especificação dos controladores na


base de dados do HyperDE e instanciação desses controladores em tempo e execução, possível graças
as facilidades de meta-programação da linguagem Ruby. As funcionalidades de persistência das classes
de modelo MyController e ControllerAction foram herdadas da classe AbstractModel que já era
implementada no HyperDE. O nome “MyController” foi escolhido no lugar de apenas “Controller”
porque o segundo é uma palavra reservada do Ruby on Rails.

A classe de controlador MyControllerController é responsável por controlar a interação com o


usuário do meta-ambiente do HyperDE no momento da criação e edição da especificação dos
controladores da aplicação. O nome desta classe segue a convenção do Ruby on Rails para
controladores que consiste em um nome CamelCase terminado com a palavra Controller e é subclasse
da classe padrão do Ruby on Rails ApplicationController, responsável pelas funcionalidades de básicas
de tratamento das requisições HTTP e renderização de páginas. Além disso, a classe
MyControllerController implementa todos os métodos do módulo CrudController, responsável pelas
operações básicas de inserção, edição, remoção e consulta no meta-ambiente do HyperDE via
requisição HTTP.
Ao instanciar um objeto da classe MyController, o HyperDE passa a ter um novo controlador e rotas
HTTP para acionamento das ações deste controlador disponíveis em seu ambiente. Este controlador
possui as mesmas características de um controlador Ruby on Rails qualquer. É importante observar que
a especificação de um novo controlador modelado através do meta-ambiente do HyperDE pode
sobrescrever os controladores estáticos (que tenham mesmo nome) já existentes no ambiente. Esta
possibilidade permite que aplicações construídas no HyperDE estendam o próprio meta-ambiente com
novas funcionalidades.
3. Código fonte
app/models/my_controller.rb
1 #
2 # * Name: MyController
3 # * Description: This class persists and instanciates the controllers
4 # specification as Rails controller classes.
5 # * Author: Mauricio Henrique de Souza Bomfim
6 # * Version: 1.0
7 #
8 class MyController < AbstractModel
9
10 #
11 # Default controller base class name.
12 # Every other controller classes should extend this class.
13 #
14 @@hyperde_base_name = "HyperdeBase"
15
16 def MyController.hyperde_base_name
17 @@hyperde_base_name
18 end
19
20 # Attributes
21 property :name
22 property :header
23 property :base_controller_id
24
25 # Relationships
26 has_many :controller_actions, :dependent => true
27 belongs_to :base_controller, :class_name => "MyController", :foreign_key =>
"base_controller_id"
28 has_many :children_controllers, :class_name => "MyController", :foreign_key =>
"base_controller_id"
29
30 # Callbacks
31 after_save :load!
32 before_destroy :validates_destroy, :unload
33
34 #
35 # Loads the controller specification as a regular Rails controller,
36 # based on its code definition.
37 #
38 def load
39 unless is_loaded?
40 begin
41 base_controller.load unless base_controller.nil?
42 Object.module_eval definition
43 children_controllers.each{|c| c.load! }
44 rescue SyntaxError => ex
45 # Nothing to do here.
46 # The syntax erro exception must not be launched.
47 end
48
49 # Setting the default route.
50 ActionController::Routing::Routes.draw do |map|
51 map.connect '%s/:action/:id' % route_name, :controller => route_name
52 end
53 end
54 end
55
56 # Forces the controller specification loading.
57 def load!
58 unload
59 load
60 end
61
62
63 # Unloads the controller.
64 def unload
65 Object.send(:remove_const, class_sym) if is_loaded?
66 end
67
68 # Checks if the controller is loaded.
69 def is_loaded?
70 (Object.const_defined?(class_sym))
71 end
72
73 #
74 # Generates the Rails controller code definition based on its specification.
75 #
76 # Example:
77 # c = MyController.new("name" => "User")
78 # action_code = %{ if User.login(params[:login], params[:password])
79 # render :text => 'ok'
80 # else
81 # render :text => 'fail'
82 # end }
83 # a = ControllerAction.new("name" => "login", "code" => action_code)
84 # c.controller_actions << a
85 # puts c.definition
86 # >>
87 # class UserController < ApplicationController
88 # def login()
89 # if User.login(params[:login], params[:password])
90 # render :text => 'ok'
91 # else
92 # render :text => 'fail'
93 # end
94 # end
95 # private
96 #
97 # end
98 #
99 def definition
100 # Generates the methods codes definitions for the public actions based
101 # on its controller action specification.
102 public_actions = controller_actions.select{|action| !action.private
}.map{ |controller_action| controller_action.definition }.join("\n\n")
103
104 # Same as above, but for private actions.
105 private_actions = controller_actions.select{|action| action.private
}.map{ |controller_action| controller_action.definition }.join("\n\n")
106
107 # Returns the class definition.
108 %{
109 class #{class_name} < #{ base_controller ? base_controller.class_name :
'ApplicationController'}
110 %s
111 %s
112
113 private
114
115 %s
116 end
117 } % [ header, public_actions, private_actions ]
118 end
119
120 # Returns the implementation name of the Rails controller class.
121 def class_name
122 "#{name}Controller"
123 end
124
125 #
126 # Returns a symbol for the Rails controller class name,
127 # required by Object methods.
128 #
129 def class_sym
130 class_name.to_sym
131 end
132
133 # Returns the route name for Rails controller.
134 def route_name
135 name.underscore
136 end
137
138 #
139 # Method called by before_destroy callback.
140 # The default controller base class must not be destroyed.
141 #
142 def validates_destroy
143 if name == @@hyperde_base_name
144 errors.add_to_base "Cannot delete #{@@hyperde_base_name} controller"
145 false
146 else
147 true
148 end
149 end
150
151 #
152 # Protected methods
153 #
154 protected
155
156 validates_format_of :name, :with => /^[A-Z][A-Za-z0-9_]*$/,
157 :message => 'Class name must start with a uppercase letter and must only
158 contain letters, digits and underscore characters'
159 #
160 # Protects the 'MyController' name.
161 # Avoid redefining the MyControllerController clas from HyperDE.
162 #
163 def validate
164 errors.add("name", "'#{name}' is a reserved name.") if name.downcase ==
'mycontroller'
165 end
166
167 end

app/models/controller_action.rb
1 #
2 # * Name: MyController
3 # * Description: This class persists the controllers actions specification
4 # and istanciates as methods of controllers classes.
5 # * Author: Mauricio Henrique de Souza Bomfim
6 # * Version: 1.0
7 #
8 class ControllerAction < AbstractModel
9
10 # Attributes
11 property :my_controller_id, "MyController"
12 property :name
13 property :params
14 property :code
15 property :private, "Boolean"
16
17 # Realationships
18 belongs_to :my_controller
19
20 # Callbacks
21 after_save :load!
22 before_destroy :unload
23 after_destroy :load!
24
25
26 # Generates the method code definition based on its specification.
27 def definition
28 %{
29 def #{name}(#{params})
30 #{code}
31 end
32 }
33 end
34
35
36 # Forces the methods's controller specification loading.
37 def load!
38 my_controller.load!
39 end
40
41 # Unloads the methods's controller.
42 def unload
43 my_controller.unload
44 end
45
46 protected
47
48 validates_format_of :name, :with => /^[a-z][A-Za-z0-9_=]*$/,
49 :message => 'Action name must start with a lowercase letter and must only
50 contain letters, digits and underscore characters'
51
52 end
app/controllers/my_controller_controller.rb
1 #
2 # * Name: MyControllerController
3 # * Description: This is the Rails controller for CRUD on my_controllers.
4 # * Author: Mauricio Henrique de Souza Bomfim
5 # * Version: 1.0
6 #
7 class MyControllerController < ApplicationController
8
9 helper :my_controller
10
11 include CrudController
12 layout "layouts/admin"
13
14 crud MyController
15
16 before_filter :before_delete, :only => [:delete]
17
18 # Actions for page titles
19 def title_for_list() "Controller List" end
20 def title_for_new() "New Controller" end
21 def title_for_edit() "Edit Controller" end
22
23 # Prepare instance variables before creating new my_controllers
24 def before_new()
25 @default_controller = MyController.find_by_name('HyperdeBase')
26 @base_controllers = MyController.find_all.reject{|c| c.id ==
@default_controller.id }.collect {|c| [c.name, c.id] }
27 end
28
29 # Prepare instance variables before editing my_controllers
30 def before_edit()
31 @default_controller = MyController.find_by_name('HyperdeBase')
32 @base_controllers = MyController.find_all.reject{|c| c.id == params[:id] or
c.id == @default_controller.id }.collect {|c| [c.name, c.id] }
33 end
34
35 def list_order() "name" end
36
37 # Validates properties before deleting a my_controller
38 def before_delete()
39
40 @my_controller = MyController.find(@params["id"])
41 unless @my_controller.validates_destroy
42 flash["notice"] = Array.new
43 @my_controller.errors.each { |attr, msg| flash["notice"] << msg }
44 redirect_to :action => "list"
45 end
46 end
47
48 def after_delete() ModelObserver.resume end
49
50 # Default notice messages
51 def notice_for_create() "Controller '#{@my_controller.name}' created. Now, add
the actions." end
52 def notice_for_update() "Controller '#{@my_controller.name}' updated." end
53 def notice_for_delete() "Controller '#{@my_controller.name}' deleted." end
54
55 def redirect_after_create() redirect_to :action => "edit", :id =>
@my_controller.id end
56
57 # All methods above are supporting actions for controller_actions
58 def new_controller_action(after_error = false)
59 @my_controller = MyController.find(@params["my_controller_id"]) unless
after_error
60 @controller_action = ControllerAction.new("my_controller" => @my_controller)
unless after_error
61 @page_title = "New action for #{@my_controller.name}"
62 render_action "edit_controller_action"
63 end
64
65 def edit_controller_action(after_error = false)
66 @my_controller = MyController.find(@params["my_controller_id"]) unless
after_error
67 @controller_action = ControllerAction.find(@params["id"]) unless after_error
68 @page_title = "Edit action for #{@my_controller.name}"
69 render_action "edit_controller_action"
70 end
71
72 def create_controller_action
73 @my_controller = MyController.find(@params["my_controller_id"])
74 @controller_action = ControllerAction.new(@params["controller_action"])
75 if @controller_action.save
76 flash["notice"] = "action #{@controller_action.name}' added."
77 redirect_to :action => "edit", :id => @params["my_controller_id"]
78 else
79 treat_errors @controller_action, "new_controller_action"
80 end
81 end
82
83 def update_controller_action
84 @my_controller = MyController.find(@params["my_controller_id"])
85 @controller_action = ControllerAction.find(@params["controller_action"]
["id"])
86 @controller_action.attributes = @params["controller_action"]
87 if @controller_action.save
88 flash["notice"] = "action '#{@controller_action.name}' updated."
89 redirect_to :action => "edit", :id => @params["my_controller_id"]
90 else
91 treat_errors @controller_action, "edit_controller_action"
92 end
93 end
94
95 def delete_controller_action
96 o = ControllerAction.find(@params["id"])
97 o.destroy
98 flash["notice"] = "action '#{o.name}' removed."
99 redirect_to :action => "edit", :id => @params["my_controller_id"]
100 end
101
102 end

app/helpers/my_controller_helper.rb
1 #
2 # * Name: MyControllerHelper
3 # * Description: This helper offer methods for controller actions forms.
4 # * Author: Mauricio Henrique de Souza Bomfim
5 # * Version: 1.0
6 #
7 module MyControllerHelper
8
9 def dg_controller_actions
10 dg = DataGrid.new(@my_controller.controller_actions, "Actions")
11 dg.actions << { :eval => "link_to('[Add New Action]', :action =>
'new_controller_action', :params => { 'my_controller_id' =>
'#{@my_controller.id}'})" }
12 dg.columns << { :label => "Name", :eval => "item.name" }
13 dg.columns << { :label => "Private", :eval => "item.private ? 'yes' : 'no' "
}
14 dg.columns << { :eval => "link_to('[Edit]', :action =>
'edit_controller_action', :id => item.id, :params => { 'my_controller_id' =>
'#{@my_controller.id}'})" }
15 dg.columns << { :eval => "link_to_confirm('[Delete]', :action =>
'delete_controller_action', :id => item.id, :params => { 'my_controller_id' =>
'#{@my_controller.id}'})" }
16 dg
17 end
18
19 end

app/views/my_controller/edit.rhtml
<!--
#
# * Name: edit.rhtml
# * Description: ERb template for editing my_controllers
# * Author: Mauricio Henrique de Souza Bomfim
# * Version: 1.0
#
-->
<form action="<%= url_for(:action => @my_controller.new_record? ? "create" :
"update") %>" method="post">

<%= hidden_field "my_controller", "id" %>

<% if @my_controller.new_record? %>


<%= render(:partial => 'shared/validation_rules', :locals => {
:my_controller => true }) %>
<p><label>Name</label>
<%= text_field("my_controller", "name", "size" => 20) %>
<% else %>
<p><label>Name</label>
<%= @my_controller.name %>
<% end %>

<% unless params[:id] == @default_controller.id %>


<p><label>Base Controller</label>
<select name="my_controller[base_controller_id]">
<option value='<%= @default_controller.id %>'>Default</option>
<%= options_for_select(@base_controllers, @my_controller.base_controller_id )
%>
</select></p>
<% end %>
<p><label>Header</label><%= text_area("my_controller", "header", "cols" =>
80, "rows" => 5) %></p>
<input type=submit value="Save">
</p>
<p><%= link_to("<< Back", :action => "list") %></p>
<hr/>

<% unless @my_controller.new_record? %>


<table><tr><td valign=top>
<%= render_helper(dg_controller_actions) %>
</td>
</tr></table>
<% end %>
</form>

app/views/my_controller/edit.rhtml
<!--
#
# * Name: list.rhtml
# * Description: ERb template for listing my_controllers
# * Author: Mauricio Henrique de Souza Bomfim
# * Version: 1.0
#
-->
<%
dg = DataGrid.new(@my_controllers)
dg.row_count = { :label => "class" }
dg.actions << { :eval => "link_to('[Add New Controller]', :action => 'new')" }
dg.columns << { :label => "Name", :eval => "item.name" }
dg.columns << { :eval => "link_to('[Edit]', :action => 'edit', :id => item.id)" }
dg.columns << { :eval => "link_to_confirm('[Delete]', :action => 'delete', :id =>
item.id)" }
%>
<%= render_helper(dg) %>

app/views/my_controller/edit_controller_action.rhtml
<!--
#
# * Name: edit_controller_action.rhtml
# * Description: ERb template for editing controllers actions
# * Author: Mauricio Henrique de Souza Bomfim
# * Version: 1.0
#
-->
<%= render(:partial => 'shared/validation_rules', :locals => { :action => true })
%>
<form action=<%= url_for(:action => @controller_action.new_record? ?
"create_controller_action" : "update_controller_action", :params => {
"my_controller_id" => @params["my_controller_id"] }) %> method="post">
<%= hidden_field "controller_action", "id" %>
<%= hidden_field "controller_action", "my_controller_id" %>
<p><label>Name</label><%= text_field("controller_action", "name", "size" => 20)
%></p>
<p><label>Parameters</label><%= text_field("controller_action", "params", "size" =>
50) %> (eg. "name, node_id")</p>
<p><label>Code</label><%= text_area("controller_action", "code", "cols" => 80,
"rows" => 20) %></p>
<p><label>Private</label><%= check_box("controller_action", "private") %></p>
<input type=submit value="Save">
</form>
<%= link_to("<< Back", :action => "edit", :id => @params["my_controller_id"]) %>

4. Testes automatizados
O framework Ruby on Rails oferece suporte completo para o desenvolvimento de testes automatizados.
Foram escritos testes automatizados para as classes de modelo apresentadas neste trabalho.

4.1. Testes
test/unit/my_controller_test.rbs
1 require 'test_helper'
2
3 class MyControllerTest < ActiveSupport::TestCase
4
5 def test_should_have_hyperde_base_controller
6
7 assert_not_nil MyController.find_by_name('HyperdeBase'), "There is no
HyperdeBase Controller"
8
9 end
10
11 def test_should_not_create_invalid_controller
12
13 test_controller = MyController.new("name" => "test")
14 assert !test_controller.save, "Class name must start with a uppercase letter
and must only contain letters, digits and underscore characters"
15
16 test_controller = MyController.new("name" => "")
17 assert !test_controller.save, "Controller saved with blank name"
18
19 assert_raises NoMethodError do
20 test_controller = MyController.new()
21 test_controller.save
22 end
23
24 end
25
26 def test_should_not_create_mycontroller
27 test = MyController.new("name" => "MyController")
28 assert !test.save, "Controller saved with MyController name"
29 end
30
31 def test_should_not_create_previews_controller
32 previews = MyController.new("name" => "Previews")
33 previews.save
34
35 previews = MyController.new("name" => "Previews")
36 assert !previews.save, "Controller saved with previews used name"
37 end
38
39 def test_should_load
40 test = MyController.new("name" => "Test")
41 assert test.load, "Controller should load"
42 end
43
44 def test_shoud_load_after_save
45 test = MyController.new("name" => "Test")
46 test.save
47 assert test.is_loaded?, "Controller should be loaded"
48 test.destroy
49 end
50
51 def test_should_not_load
52 test = MyController.new("name" => "Test")
53 test.header = "a=" #syntax error
54 assert !test.load, "Controller should not load"
55 end
56
57 def test_is_loaded
58 test = MyController.new("name" => "TestLoad")
59 assert !test.is_loaded?
60 test.load
61 assert test.is_loaded?
62 test.unload
63 end
64
65 def test_unload
66 test = MyController.new("name" => "Test")
67 test.load
68 assert test.is_loaded?
69 test.unload
70 assert !test.is_loaded?
71 end
72
73 def test_class_name
74 test = MyController.new("name" => "TestName")
75 assert_equal test.class_name, "TestNameController"
76 end
77
78 def test_class_sym
79 test = MyController.new("name" => "TestName")
80 assert_equal test.class_sym, :TestNameController
81 end
82
83 def test_route_name
84 test = MyController.new("name" => "TestName")
85 assert_equal test.route_name, "test_name"
86 end
87
88 def test_definition
89 test = MyController.new("name" => "TestName")
90 definition = "\n\t\t\tclass TestNameController <
ApplicationController\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tprivate\n\t\t\t\t\n\t\
t\t\t\n\t\t\tend\n\t\t"
91 assert_equal test.definition, definition
92
93 definition = "\n\t\t\tclass TestNameController <
ApplicationController\n\t\t\t\t\n\t\t\t\t\n \t\t\tdef test_action()\n
\t\t\t\t1\n \t\t\tend\n
\t\t\n\t\t\t\t\n\t\t\t\tprivate\n\t\t\t\t\n\t\t\t\t\n\t\t\tend\n\t\t"
94 test.controller_actions << ControllerAction.new("name" => "test_action",
"code" => "1")
95 assert_equal test.definition, definition
96
97 definition = "\n\t\t\tclass TestNameController <
ApplicationController\n\t\t\t\t\n\t\t\t\t\n \t\t\tdef test_action()\n
\t\t\t\t1\n \t\t\tend\n \t\t\n\t\t\t\t\n\t\t\t\tprivate\n\t\t\t\t\n\t\t\t\t\n
\t\t\tdef test_private_action()\n \t\t\t\t2\n \t\t\tend\n \t\t\n\t\t\tend\n\t\t"
98 test.controller_actions << ControllerAction.new("name" =>
"test_private_action", "code" => "2", "private" => true)
99 assert_equal test.definition, definition
100
101 definition = "\n\t\t\tclass TestNameController <
ApplicationController\n\t\t\t\tbefore_filter :test\n\t\t\t\t\n \t\t\tdef
test_action()\n \t\t\t\t1\n \t\t\tend\n
\t\t\n\t\t\t\t\n\t\t\t\tprivate\n\t\t\t\t\n\t\t\t\t\n \t\t\tdef
test_private_action()\n \t\t\t\t2\n \t\t\tend\n \t\t\n\t\t\tend\n\t\t"
102 test.header = "before_filter :test"
103 assert_equal test.definition, definition
104
105 end
106
107 def test_should_not_destroy_hyperdebase
108 base = MyController.find_by_name("HyperdeBase")
109 assert !base.destroy, "Allows destroy HyperdeBase Controller"
110 end
111
112 end

test/unit/controller_action_test.rb
1 require 'test_helper'
2
3 class ControllerActionTest < ActiveSupport::TestCase
4
5 def test_definition
6 test = ControllerAction.new("name" => "test", "code" => "1 + 1")
7 definition = "\n \t\t\tdef test()\n \t\t\t\t1 + 1\n \t\t\tend\n \t\t"
8 assert_equal test.definition, definition
9
10 test.params = "a, b, c"
11 definition = "\n \t\t\tdef test(a, b, c)\n \t\t\t\t1 + 1\n \t\t\tend\n \t\t"
12 assert_equal test.definition, definition
13
14 end
15
16 def test_should_load
17 test_controller = MyController.new("name" => "Test")
18 test_action = ControllerAction.new("name" => "test_action", "code" => "1")
19 test_controller.controller_actions << test_action
20 test_action.my_controller = test_controller
21 test_action.load!
22 assert TestController.instance_methods.include?('test_action')
23 end
24
25 end

4.2. Logs de testes


ruby unit/my_controller_test.rb -v
Running from unit/my_controller_test.rb...
Loaded suite unit/my_controller_test
Started
test_class_name(MyControllerTest): .
test_class_sym(MyControllerTest): .
test_definition(MyControllerTest): .
test_is_loaded(MyControllerTest): .
test_route_name(MyControllerTest): .
test_shoud_load_after_save(MyControllerTest): .
test_should_have_hyperde_base_controller(MyControllerTest): .
test_should_load(MyControllerTest): .
test_should_not_create_invalid_controller(MyControllerTest): .
test_should_not_create_mycontroller(MyControllerTest): .
test_should_not_create_previews_controller(MyControllerTest): .
test_should_not_destroy_hyperdebase(MyControllerTest): .
test_should_not_load(MyControllerTest): .
test_unload(MyControllerTest): .

Finished in 0.093 seconds.

14 tests, 21 assertions, 0 failures, 0 errors

ruby unit/controller_action_test.rb -v
Running from unit/controller_action_test.rb...
Loaded suite unit/controller_action_test
Started
test_definition(ControllerActionTest): .
test_should_load(ControllerActionTest): .

Finished in 0.0 seconds.

2 tests, 3 assertions, 0 failures, 0 errors


5. Guia do usuário

5.1. Instalação
1. Instale a última versão do Ruby. Para windows instale o One-Click Ruby Installer
http://rubyforge.org/projects/rubyinstaller/
2. Instale o Rails 2.3.4 com o comando 'gem install rails -v=2.3.4'
3. Instale a biblioteca RJB com o comando 'gem install rjb'. Esta biblioteca depende do java.
4. Copie a pasta /hyperde, disponível no cd para o seu computador, em um diretório de sua
preferência.
5. Para executar o servidor da aplicação, entre na pasta onde instalou o HyperDE e execute o
comando ruby script/server.
6. Acesse a aplicação pelo seu navegador internet na url http://localhost:3000. Você verá a
seguinte página:

5.2. Usando controladores


Para ilustrar esta funcionalidade, vamos criar um controlador cujo objetivo é oferecer serviços de
cálculos matemáticos básicos. Criaremos quatro ações, uma para cada operação básica da matemática,
usando um parâmetro de entrada e efetuando a operação com o valor 2.
a) Criando um controlador
1. Acesse o meta-ambiente clicando em “Go to Metamodel”
2. Em seguida clique no link “Controllers” e depois no link “Add New Controller”.
3. Criaremos um controlador chamado “Math”. Preencha o formulário conforme a imagem abaixo,
e em seguida clique no botão “Save”.

b) Criando uma ação


1. Após criar o controlador, a tela de edição do mesmo será automaticamente acessada. Nesta tela,
clique no link “Add New Action”.
2. Vamos criar a ação “sum”, cujo código é render :text => params[:id].to_i + 2. Preencha o
formulário conforme a imagem abaixo e clique em “Save”.
3. Acesse a url http://localhost:3000/math/sum/3 para obter o resultado “5”.
4. Você pode seguir o mesmo procedimento para as ações subitração, multiplicação e divisão.
c) Observações
O campo “Header” do Controller serve para indicar filtros do Rails que entram em ação antes
ou depois da execução das ações. É possível, através do filtro “before_filter” indicar que antes de
qualquer ação, um método de autenticação será executado. Veja a API do Rails para mais detalhes.
O campo “private” do Controller Action indica que a ação não é acessível via url, e está
disponível apenas para uso através de outras ações públicas.

Potrebbero piacerti anche