<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cshao</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cshao"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Cshao"/>
	<updated>2026-08-23T06:37:50Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112669</id>
		<title>CSC/ECE 517 Fall 2017/E17A6 Fix account creation over web to work reasonably</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112669"/>
		<updated>2017-11-08T04:26:41Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Use Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==  '''Introduction to Expertiza''' ==&lt;br /&gt;
Expertiza[https://expertiza.ncsu.edu/wiki/] is a project developed using Ruby on Rails[https://en.wikipedia.org/wiki/Ruby_on_Rails]. It provides features like peer review, team assignments and submission of projects. This can be achieved by submitting code base, URL of hosted code on remote server and Wiki submissions. It is an open source application and the code can be cloned from GitHub[https://en.wikipedia.org/wiki/GitHub]. This application provides an efficient way to manage assignments, grades and reviews. This makes the process easier and faster when the class strength is large.&lt;br /&gt;
== '''Introduction''' ==&lt;br /&gt;
=== '''Purpose''' ===&lt;br /&gt;
Expertiza provide the function for user to request an account, but the function is not perfect. The goal of our project is to improve this feature. It will enable Expertiza to handle the pending request for super-admin and add institution for user.&lt;br /&gt;
&lt;br /&gt;
=== '''Problem Definition''' ===&lt;br /&gt;
===='''New user request page'''====&lt;br /&gt;
*Currently, a new user can only choose institution from the dropdown. The new user should be able to add a new institution. &lt;br /&gt;
*A place where a new user to write a brief introduction is needed in this page.&lt;br /&gt;
*Also, in models/requested_user.rb, there are some validations, such as validate email address. It will be better to update the flash message on the view when validation fails.&lt;br /&gt;
===='''Super-admin and admin are able to approve or decline new user requests. '''====&lt;br /&gt;
*Currently, you have to go to /users/list_pending_requested this url to access a list of pending requests. It will be better to add an option in “Administration &amp;gt; Show…” menu &lt;br /&gt;
*Make “Email Address” column in /users/list_pending_requested page clickable. So that super-admin or admin could converse with requesters by clicking email addresses directly.&lt;br /&gt;
===='''After approving'''====&lt;br /&gt;
*After super-admin or admin approves the request, make sure the record does not disappear on the page. And there should be an email send to email address offered by requester.&lt;br /&gt;
&lt;br /&gt;
== '''Requirements''' ==&lt;br /&gt;
*Modify the test of request new user method. &lt;br /&gt;
*Add a new option for the drop-down bar of institution in the new user request page.&lt;br /&gt;
*Add a new textarea in the new user request page, to input a new institution and introduction.&lt;br /&gt;
*Add validation for new institution new institutions and introductions.&lt;br /&gt;
*Add flash message for requested_user.rb.&lt;br /&gt;
*Add a new button on the layout.&lt;br /&gt;
*Modify the layout of /users/list_pending_requested page.&lt;br /&gt;
*Enable the system will send an email after the request is processed.&lt;br /&gt;
&lt;br /&gt;
=='''Database Design'''==&lt;br /&gt;
[[File:17a61.JPG]]&lt;br /&gt;
*The above tables is the original table for this project, however it lacks a column for introduction. So we need to add a new column for request_user table. The new table will be shown below.&lt;br /&gt;
[[File:17a62.JPG]]&lt;br /&gt;
&lt;br /&gt;
=='''Use Cases'''==&lt;br /&gt;
[[File:Expertiza_Use_Case_for_New_Account_Request.png]]&lt;br /&gt;
&lt;br /&gt;
[[File:17a6e.JPG]]&lt;br /&gt;
*Name: Instructor or Teaching Assistant request a new account&lt;br /&gt;
*Actor: Instructor or Teaching Assistant&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: None&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Click on “Request account”.&lt;br /&gt;
::2. Select a role.&lt;br /&gt;
::3. Fill in a user name.&lt;br /&gt;
::4. Fill in a full name.&lt;br /&gt;
::5. Fill in an email address.&lt;br /&gt;
::6. Select an institution.&lt;br /&gt;
::7. Fill in the introduction field.&lt;br /&gt;
::8. Click on “Request”.&lt;br /&gt;
*Alternative Flow:&lt;br /&gt;
::1. If the institution not in the list, click on “Others”.&lt;br /&gt;
::2. Fill in the institution name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin view list of new account requests&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza.&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. View the list of new account requests.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin accept a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza.&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on “Accept”.&lt;br /&gt;
::5. Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin reject a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on “Reject”.&lt;br /&gt;
::5. Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin send an email to applicant&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on the email address.&lt;br /&gt;
::5. Write the email.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
=='''Design Pattern'''==&lt;br /&gt;
==='''MVC'''===&lt;br /&gt;
The project is implemented in Ruby on Rails that uses MVC architecture. It separates an application’s data model, user interface, and control logic into three distinct components (model, view and controller, respectively).&lt;br /&gt;
&lt;br /&gt;
==='''TDD'''===&lt;br /&gt;
In this project, we follow the Test-driven development (TDD) software development process, which means that we would first write a test that fails before you write new functional code.&lt;br /&gt;
&lt;br /&gt;
==='''DIY'''===&lt;br /&gt;
We are trying to reuse the existing functionalities in Expertiza, thus avoiding code duplication. Whenever possible, code modification based on the existing classes, controllers, or tables will be done instead of creating the new one.&lt;br /&gt;
&lt;br /&gt;
=='''Mockup Screen'''==&lt;br /&gt;
Below are the mock-up screens that explain “new account acreation” functionality in Expertiza. &lt;br /&gt;
*1.New user should click “request account” for requesting a new account, then redirect to the “request new ” page.&lt;br /&gt;
[[File:17a65.jpg]]&lt;br /&gt;
*2.After redirect to “request new ” page, new users should enter their information, includes role, name, e-mail and institution. If the institution that new users want to choose is not in the list, we can choose “others” option, then a textbox will appear. We can enter our new institution in this textbox. Finally, we can click “request” button to submit our request, and wait for being approved by administrator. &lt;br /&gt;
[[File:17a66.jpg]]&lt;br /&gt;
*3. If we login as administrator, we can see the screens below.&lt;br /&gt;
[[File:17a67.jpg]]&lt;br /&gt;
*4. If we click “show requests”, we can see this screen. The email address is clickable.&lt;br /&gt;
[[File:17a68.jpg]]&lt;br /&gt;
*5.If we click the email address, the email editor will pop out. Administrator can converse with requestor directly.&lt;br /&gt;
[[File:17a6a.jpg]]&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza_Use_Case_for_New_Account_Request.png&amp;diff=112668</id>
		<title>File:Expertiza Use Case for New Account Request.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Expertiza_Use_Case_for_New_Account_Request.png&amp;diff=112668"/>
		<updated>2017-11-08T04:25:36Z</updated>

		<summary type="html">&lt;p&gt;Cshao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112661</id>
		<title>CSC/ECE 517 Fall 2017/E17A6 Fix account creation over web to work reasonably</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112661"/>
		<updated>2017-11-08T04:19:38Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Use Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==  '''Introduction to Expertiza''' ==&lt;br /&gt;
Expertiza[https://expertiza.ncsu.edu/wiki/] is a project developed using Ruby on Rails[https://en.wikipedia.org/wiki/Ruby_on_Rails]. It provides features like peer review, team assignments and submission of projects. This can be achieved by submitting code base, URL of hosted code on remote server and Wiki submissions. It is an open source application and the code can be cloned from GitHub[https://en.wikipedia.org/wiki/GitHub]. This application provides an efficient way to manage assignments, grades and reviews. This makes the process easier and faster when the class strength is large.&lt;br /&gt;
== '''Introduction''' ==&lt;br /&gt;
=== '''Purpose''' ===&lt;br /&gt;
Expertiza provide the function for user to request an account, but the function is not perfect. The goal of our project is to improve this feature. It will enable Expertiza to handle the pending request for super-admin and add institution for user.&lt;br /&gt;
&lt;br /&gt;
=== '''Problem Definition''' ===&lt;br /&gt;
===='''New user request page'''====&lt;br /&gt;
*Currently, a new user can only choose institution from the dropdown. The new user should be able to add a new institution. &lt;br /&gt;
*A place where a new user to write a brief introduction is needed in this page.&lt;br /&gt;
*Also, in models/requested_user.rb, there are some validations, such as validate email address. It will be better to update the flash message on the view when validation fails.&lt;br /&gt;
===='''Super-admin and admin are able to approve or decline new user requests. '''====&lt;br /&gt;
*Currently, you have to go to /users/list_pending_requested this url to access a list of pending requests. It will be better to add an option in “Administration &amp;gt; Show…” menu &lt;br /&gt;
*Make “Email Address” column in /users/list_pending_requested page clickable. So that super-admin or admin could converse with requesters by clicking email addresses directly.&lt;br /&gt;
===='''After approving'''====&lt;br /&gt;
*After super-admin or admin approves the request, make sure the record does not disappear on the page. And there should be an email send to email address offered by requester.&lt;br /&gt;
&lt;br /&gt;
== '''Requirements''' ==&lt;br /&gt;
*Modify the test of request new user method. &lt;br /&gt;
*Add a new option for the drop-down bar of institution in the new user request page.&lt;br /&gt;
*Add a new textarea in the new user request page, to input a new institution and introduction.&lt;br /&gt;
*Add validation for new institution new institutions and introductions.&lt;br /&gt;
*Add flash message for requested_user.rb.&lt;br /&gt;
*Add a new button on the layout.&lt;br /&gt;
*Modify the layout of /users/list_pending_requested page.&lt;br /&gt;
*Enable the system will send an email after the request is processed.&lt;br /&gt;
&lt;br /&gt;
=='''Database Design'''==&lt;br /&gt;
[[File:17a61.JPG]]&lt;br /&gt;
*The above tables is the original table for this project, however it lacks a column for introduction. So we need to add a new column for request_user table. The new table will be shown below.&lt;br /&gt;
[[File:17a62.JPG]]&lt;br /&gt;
&lt;br /&gt;
=='''Use Cases'''==&lt;br /&gt;
[[File:17a6b.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:17a6e.JPG]]&lt;br /&gt;
*Name: Instructor or Teaching Assistant request a new account&lt;br /&gt;
*Actor: Instructor or Teaching Assistant&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: None&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Click on “Request account”.&lt;br /&gt;
::2. Select a role.&lt;br /&gt;
::3. Fill in a user name.&lt;br /&gt;
::4. Fill in a full name.&lt;br /&gt;
::5. Fill in an email address.&lt;br /&gt;
::6. Select an institution.&lt;br /&gt;
::7. Fill in the introduction field.&lt;br /&gt;
::8. Click on “Request”.&lt;br /&gt;
*Alternative Flow:&lt;br /&gt;
::1. If the institution not in the list, click on “Others”.&lt;br /&gt;
::2. Fill in the institution name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin view list of new account requests&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza.&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. View the list of new account requests.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin accept a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza.&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on “Accept”.&lt;br /&gt;
::5. Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin reject a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on “Reject”.&lt;br /&gt;
::5. Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin send an email to applicant&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on the email address.&lt;br /&gt;
::5. Write the email.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
=='''Design Pattern'''==&lt;br /&gt;
==='''MVC'''===&lt;br /&gt;
The project is implemented in Ruby on Rails that uses MVC architecture. It separates an application’s data model, user interface, and control logic into three distinct components (model, view and controller, respectively).&lt;br /&gt;
&lt;br /&gt;
==='''TDD'''===&lt;br /&gt;
In this project, we follow the Test-driven development (TDD) software development process, which means that we would first write a test that fails before you write new functional code.&lt;br /&gt;
&lt;br /&gt;
==='''DIY'''===&lt;br /&gt;
We are trying to reuse the existing functionalities in Expertiza, thus avoiding code duplication. Whenever possible, code modification based on the existing classes, controllers, or tables will be done instead of creating the new one.&lt;br /&gt;
&lt;br /&gt;
=='''Mockup Screen'''==&lt;br /&gt;
Below are the mock-up screens that explain “new account acreation” functionality in Expertiza. &lt;br /&gt;
*1.New user should click “request account” for requesting a new account, then redirect to the “request new ” page.&lt;br /&gt;
[[File:17a65.jpg]]&lt;br /&gt;
*2.After redirect to “request new ” page, new users should enter their information, includes role, name, e-mail and institution. If the institution that new users want to choose is not in the list, we can choose “others” option, then a textbox will appear. We can enter our new institution in this textbox. Finally, we can click “request” button to submit our request, and wait for being approved by administrator. &lt;br /&gt;
[[File:17a66.jpg]]&lt;br /&gt;
*3. If we login as administrator, we can see the screens below.&lt;br /&gt;
[[File:17a67.jpg]]&lt;br /&gt;
*4. If we click “show requests”, we can see this screen. The email address is clickable.&lt;br /&gt;
[[File:17a68.jpg]]&lt;br /&gt;
*5.If we click the email address, the email editor will pop out. Administrator can converse with requestor directly.&lt;br /&gt;
[[File:17a6a.jpg]]&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112116</id>
		<title>CSC/ECE 517 Fall 2017/E17A6 Fix account creation over web to work reasonably</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112116"/>
		<updated>2017-11-07T02:11:31Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Use Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==  '''Introduction to Expertiza''' ==&lt;br /&gt;
Expertiza[https://expertiza.ncsu.edu/wiki/] is a project developed using Ruby on Rails[https://en.wikipedia.org/wiki/Ruby_on_Rails]. It provides features like peer review, team assignments and submission of projects. This can be achieved by submitting code base, URL of hosted code on remote server and Wiki submissions. It is an open source application and the code can be cloned from GitHub[https://en.wikipedia.org/wiki/GitHub]. This application provides an efficient way to manage assignments, grades and reviews. This makes the process easier and faster when the class strength is large.&lt;br /&gt;
== '''Introduction''' ==&lt;br /&gt;
=== '''Purpose''' ===&lt;br /&gt;
Expertiza provide the function for user to request an account, but the function is not perfect. The goal of our project is to improve this feature. It will enable Expertiza to handle the pending request for super-admin and add institution for user.&lt;br /&gt;
&lt;br /&gt;
=== '''Problem Definition''' ===&lt;br /&gt;
===='''New user request page'''====&lt;br /&gt;
*Currently, a new user can only choose institution from the dropdown. The new user should be able to add a new institution. &lt;br /&gt;
*A place where a new user to write a brief introduction is needed in this page.&lt;br /&gt;
*Also, in models/requested_user.rb, there are some validations, such as validate email address. It will be better to update the flash message on the view when validation fails.&lt;br /&gt;
===='''Super-admin and admin are able to approve or decline new user requests. '''====&lt;br /&gt;
*Currently, you have to go to /users/list_pending_requested this url to access a list of pending requests. It will be better to add an option in “Administration &amp;gt; Show…” menu &lt;br /&gt;
*Make “Email Address” column in /users/list_pending_requested page clickable. So that super-admin or admin could converse with requesters by clicking email addresses directly.&lt;br /&gt;
===='''After approving'''====&lt;br /&gt;
*After super-admin or admin approves the request, make sure the record does not disappear on the page. And there should be an email send to email address offered by requester.&lt;br /&gt;
&lt;br /&gt;
== '''Requirements''' ==&lt;br /&gt;
*Modify the test of request new user method. &lt;br /&gt;
*Add a new option for the drop-down bar of institution in the new user request page.&lt;br /&gt;
*Add a new textarea in the new user request page, to input a new institution and introduction.&lt;br /&gt;
*Add validation for new institution new institutions and introductions.&lt;br /&gt;
*Add flash message for requested_user.rb.&lt;br /&gt;
*Add a new button on the layout.&lt;br /&gt;
*Modify the layout of /users/list_pending_requested page.&lt;br /&gt;
*Enable the system will send an email after the request is processed.&lt;br /&gt;
&lt;br /&gt;
=='''Database Design'''==&lt;br /&gt;
[[File:17a61.JPG]]&lt;br /&gt;
*The above tables is the original table for this project, however it lacks a column for introduction. So we need to add a new column for request_user table. The new table will be shown below.&lt;br /&gt;
[[File:17a62.JPG]]&lt;br /&gt;
&lt;br /&gt;
=='''Use Cases'''==&lt;br /&gt;
[[File:17a63.jpg]]&lt;br /&gt;
*Name: Instructor or Teaching Assistant request a new account&lt;br /&gt;
*Actor: Instructor or Teaching Assistant&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: None&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Click on “Request account”.&lt;br /&gt;
::2. Select a role.&lt;br /&gt;
::3. Fill in a user name.&lt;br /&gt;
::4. Fill in a full name.&lt;br /&gt;
::5. Fill in an email address.&lt;br /&gt;
::6. Select an institution.&lt;br /&gt;
::7. Fill in the introduction field.&lt;br /&gt;
::8. Click on “Request”.&lt;br /&gt;
*Alternative Flow:&lt;br /&gt;
::6.1 If the institution not in the list, click on “Others”.&lt;br /&gt;
::6.2 Fill in the institution name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin view list of new account requests&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza.&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. View the list of new account requests.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin accept a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza.&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on “Accept”.&lt;br /&gt;
::5. Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin reject a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on “Reject”.&lt;br /&gt;
::5. Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin send an email to applicant&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on the email address.&lt;br /&gt;
::5. Write the email.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
=='''Design Pattern'''==&lt;br /&gt;
==='''MVC'''===&lt;br /&gt;
The project is implemented in Ruby on Rails that uses MVC architecture. It separates an application’s data model, user interface, and control logic into three distinct components (model, view and controller, respectively).&lt;br /&gt;
&lt;br /&gt;
==='''TDD'''===&lt;br /&gt;
In this project, we follow the Test-driven development (TDD) software development process, which means that we would first write a test that fails before you write new functional code.&lt;br /&gt;
&lt;br /&gt;
==='''DIY'''===&lt;br /&gt;
We are trying to reuse the existing functionalities in Expertiza, thus avoiding code duplication. Whenever possible, code modification based on the existing classes, controllers, or tables will be done instead of creating the new one.&lt;br /&gt;
&lt;br /&gt;
=='''Mockup Screen'''==&lt;br /&gt;
Below are the mock-up screens that explain “new account acreation” functionality in Expertiza. &lt;br /&gt;
*1.New user should click “request account” for requesting a new account, then redirect to the “request new ” page.&lt;br /&gt;
[[File:17a65.jpg]]&lt;br /&gt;
*2.After redirect to “request new ” page, new users should enter their information, includes role, name, e-mail and institution. If the institution that new users want to choose is not in the list, we can choose “others” option, then a textbox will appear. We can enter our new institution in this textbox. Finally, we can click “request” button to submit our request, and wait for being approved by administrator. &lt;br /&gt;
[[File:17a66.jpg]]&lt;br /&gt;
*3. If we login as administrator, we can see the screens below.&lt;br /&gt;
[[File:17a67.jpg]]&lt;br /&gt;
*4. If we click “show requests”, we can see this screen. The email address is clickable.&lt;br /&gt;
[[File:17a68.jpg]]&lt;br /&gt;
*5.If we click the email address, the email editor will pop out. Administrator can converse with requestor directly.&lt;br /&gt;
[[File:17a6a.jpg]]&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112115</id>
		<title>CSC/ECE 517 Fall 2017/E17A6 Fix account creation over web to work reasonably</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112115"/>
		<updated>2017-11-07T02:11:00Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Use Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==  '''Introduction to Expertiza''' ==&lt;br /&gt;
Expertiza[https://expertiza.ncsu.edu/wiki/] is a project developed using Ruby on Rails[https://en.wikipedia.org/wiki/Ruby_on_Rails]. It provides features like peer review, team assignments and submission of projects. This can be achieved by submitting code base, URL of hosted code on remote server and Wiki submissions. It is an open source application and the code can be cloned from GitHub[https://en.wikipedia.org/wiki/GitHub]. This application provides an efficient way to manage assignments, grades and reviews. This makes the process easier and faster when the class strength is large.&lt;br /&gt;
== '''Introduction''' ==&lt;br /&gt;
=== '''Purpose''' ===&lt;br /&gt;
Expertiza provide the function for user to request an account, but the function is not perfect. The goal of our project is to improve this feature. It will enable Expertiza to handle the pending request for super-admin and add institution for user.&lt;br /&gt;
&lt;br /&gt;
=== '''Problem Definition''' ===&lt;br /&gt;
===='''New user request page'''====&lt;br /&gt;
*Currently, a new user can only choose institution from the dropdown. The new user should be able to add a new institution. &lt;br /&gt;
*A place where a new user to write a brief introduction is needed in this page.&lt;br /&gt;
*Also, in models/requested_user.rb, there are some validations, such as validate email address. It will be better to update the flash message on the view when validation fails.&lt;br /&gt;
===='''Super-admin and admin are able to approve or decline new user requests. '''====&lt;br /&gt;
*Currently, you have to go to /users/list_pending_requested this url to access a list of pending requests. It will be better to add an option in “Administration &amp;gt; Show…” menu &lt;br /&gt;
*Make “Email Address” column in /users/list_pending_requested page clickable. So that super-admin or admin could converse with requesters by clicking email addresses directly.&lt;br /&gt;
===='''After approving'''====&lt;br /&gt;
*After super-admin or admin approves the request, make sure the record does not disappear on the page. And there should be an email send to email address offered by requester.&lt;br /&gt;
&lt;br /&gt;
== '''Requirements''' ==&lt;br /&gt;
*Modify the test of request new user method. &lt;br /&gt;
*Add a new option for the drop-down bar of institution in the new user request page.&lt;br /&gt;
*Add a new textarea in the new user request page, to input a new institution and introduction.&lt;br /&gt;
*Add validation for new institution new institutions and introductions.&lt;br /&gt;
*Add flash message for requested_user.rb.&lt;br /&gt;
*Add a new button on the layout.&lt;br /&gt;
*Modify the layout of /users/list_pending_requested page.&lt;br /&gt;
*Enable the system will send an email after the request is processed.&lt;br /&gt;
&lt;br /&gt;
=='''Database Design'''==&lt;br /&gt;
[[File:17a61.JPG]]&lt;br /&gt;
*The above tables is the original table for this project, however it lacks a column for introduction. So we need to add a new column for request_user table. The new table will be shown below.&lt;br /&gt;
[[File:17a62.JPG]]&lt;br /&gt;
&lt;br /&gt;
=='''Use Cases'''==&lt;br /&gt;
[[File:17a63.jpg]]&lt;br /&gt;
*Name: Instructor or Teaching Assistant request a new account&lt;br /&gt;
*Actor: Instructor or Teaching Assistant&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: None&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Click on “Request account”.&lt;br /&gt;
::2. Select a role.&lt;br /&gt;
::3. Fill in a user name.&lt;br /&gt;
::4. Fill in a full name.&lt;br /&gt;
::5. Fill in an email address.&lt;br /&gt;
::6. Select an institution.&lt;br /&gt;
::7. Fill in the introduction field.&lt;br /&gt;
::8. Click on “Request”.&lt;br /&gt;
*Alternative Flow:&lt;br /&gt;
::6.1. If the institution not in the list, click on “Others”.&lt;br /&gt;
::6.2. Fill in the institution name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin view list of new account requests&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza.&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. View the list of new account requests.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin accept a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza.&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on “Accept”.&lt;br /&gt;
::5. Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin reject a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on “Reject”.&lt;br /&gt;
::5. Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin send an email to applicant&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1. Log in to Expertiza&lt;br /&gt;
::2. Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3. Select a request.&lt;br /&gt;
::4. Click on the email address.&lt;br /&gt;
::5. Write the email.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
=='''Design Pattern'''==&lt;br /&gt;
==='''MVC'''===&lt;br /&gt;
The project is implemented in Ruby on Rails that uses MVC architecture. It separates an application’s data model, user interface, and control logic into three distinct components (model, view and controller, respectively).&lt;br /&gt;
&lt;br /&gt;
==='''TDD'''===&lt;br /&gt;
In this project, we follow the Test-driven development (TDD) software development process, which means that we would first write a test that fails before you write new functional code.&lt;br /&gt;
&lt;br /&gt;
==='''DIY'''===&lt;br /&gt;
We are trying to reuse the existing functionalities in Expertiza, thus avoiding code duplication. Whenever possible, code modification based on the existing classes, controllers, or tables will be done instead of creating the new one.&lt;br /&gt;
&lt;br /&gt;
=='''Mockup Screen'''==&lt;br /&gt;
Below are the mock-up screens that explain “new account acreation” functionality in Expertiza. &lt;br /&gt;
*1.New user should click “request account” for requesting a new account, then redirect to the “request new ” page.&lt;br /&gt;
[[File:17a65.jpg]]&lt;br /&gt;
*2.After redirect to “request new ” page, new users should enter their information, includes role, name, e-mail and institution. If the institution that new users want to choose is not in the list, we can choose “others” option, then a textbox will appear. We can enter our new institution in this textbox. Finally, we can click “request” button to submit our request, and wait for being approved by administrator. &lt;br /&gt;
[[File:17a66.jpg]]&lt;br /&gt;
*3. If we login as administrator, we can see the screens below.&lt;br /&gt;
[[File:17a67.jpg]]&lt;br /&gt;
*4. If we click “show requests”, we can see this screen. The email address is clickable.&lt;br /&gt;
[[File:17a68.jpg]]&lt;br /&gt;
*5.If we click the email address, the email editor will pop out. Administrator can converse with requestor directly.&lt;br /&gt;
[[File:17a6a.jpg]]&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112113</id>
		<title>CSC/ECE 517 Fall 2017/E17A6 Fix account creation over web to work reasonably</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112113"/>
		<updated>2017-11-07T02:08:40Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Use Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==  '''Introduction to Expertiza''' ==&lt;br /&gt;
Expertiza[https://expertiza.ncsu.edu/wiki/] is a project developed using Ruby on Rails[https://en.wikipedia.org/wiki/Ruby_on_Rails]. It provides features like peer review, team assignments and submission of projects. This can be achieved by submitting code base, URL of hosted code on remote server and Wiki submissions. It is an open source application and the code can be cloned from GitHub[https://en.wikipedia.org/wiki/GitHub]. This application provides an efficient way to manage assignments, grades and reviews. This makes the process easier and faster when the class strength is large.&lt;br /&gt;
== '''Introduction''' ==&lt;br /&gt;
=== '''Purpose''' ===&lt;br /&gt;
Expertiza provide the function for user to request an account, but the function is not perfect. The goal of our project is to improve this feature. It will enable Expertiza to handle the pending request for super-admin and add institution for user.&lt;br /&gt;
&lt;br /&gt;
=== '''Problem Definition''' ===&lt;br /&gt;
===='''New user request page'''====&lt;br /&gt;
*Currently, a new user can only choose institution from the dropdown. The new user should be able to add a new institution. &lt;br /&gt;
*A place where a new user to write a brief introduction is needed in this page.&lt;br /&gt;
*Also, in models/requested_user.rb, there are some validations, such as validate email address. It will be better to update the flash message on the view when validation fails.&lt;br /&gt;
===='''Super-admin and admin are able to approve or decline new user requests. '''====&lt;br /&gt;
*Currently, you have to go to /users/list_pending_requested this url to access a list of pending requests. It will be better to add an option in “Administration &amp;gt; Show…” menu &lt;br /&gt;
*Make “Email Address” column in /users/list_pending_requested page clickable. So that super-admin or admin could converse with requesters by clicking email addresses directly.&lt;br /&gt;
===='''After approving'''====&lt;br /&gt;
*After super-admin or admin approves the request, make sure the record does not disappear on the page. And there should be an email send to email address offered by requester.&lt;br /&gt;
&lt;br /&gt;
== '''Requirements''' ==&lt;br /&gt;
*Modify the test of request new user method. &lt;br /&gt;
*Add a new option for the drop-down bar of institution in the new user request page.&lt;br /&gt;
*Add a new textarea in the new user request page, to input a new institution and introduction.&lt;br /&gt;
*Add validation for new institution new institutions and introductions.&lt;br /&gt;
*Add flash message for requested_user.rb.&lt;br /&gt;
*Add a new button on the layout.&lt;br /&gt;
*Modify the layout of /users/list_pending_requested page.&lt;br /&gt;
*Enable the system will send an email after the request is processed.&lt;br /&gt;
&lt;br /&gt;
=='''Database Design'''==&lt;br /&gt;
[[File:17a61.JPG]]&lt;br /&gt;
*The above tables is the original table for this project, however it lacks a column for introduction. So we need to add a new column for request_user table. The new table will be shown below.&lt;br /&gt;
[[File:17a62.JPG]]&lt;br /&gt;
&lt;br /&gt;
=='''Use Cases'''==&lt;br /&gt;
[[File:17a63.jpg]]&lt;br /&gt;
*Name: Instructor or Teaching Assistant request a new account&lt;br /&gt;
*Actor: Instructor or Teaching Assistant&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: None&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Click on “Request account”.&lt;br /&gt;
::2.Select a role.&lt;br /&gt;
::3.Fill in a user name.&lt;br /&gt;
::4.Fill in a full name.&lt;br /&gt;
::5.Fill in an email address.&lt;br /&gt;
::6.Select an institution.&lt;br /&gt;
::7.Fill in the introduction field.&lt;br /&gt;
::8.Click on “Request”.&lt;br /&gt;
*Alternative Flow:&lt;br /&gt;
::6.1.If the institution not in the list, click on “Others”.&lt;br /&gt;
::6.2.Fill in the institution name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin view list of new account requests&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Log in to Expertiza.&lt;br /&gt;
::2.Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3.View the list of new account requests.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin accept a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Log in to Expertiza.&lt;br /&gt;
::2.Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3.Select a request.&lt;br /&gt;
::4.Click on “Accept”.&lt;br /&gt;
::5.Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin reject a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Log in to Expertiza&lt;br /&gt;
::2.Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3.Select a request.&lt;br /&gt;
::4.Click on “Reject”.&lt;br /&gt;
::5.Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin send an email to applicant&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Log in to Expertiza&lt;br /&gt;
::2.Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3.Select a request.&lt;br /&gt;
::4.Click on the email address.&lt;br /&gt;
::5.Write the email.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
=='''Design Pattern'''==&lt;br /&gt;
==='''MVC'''===&lt;br /&gt;
The project is implemented in Ruby on Rails that uses MVC architecture. It separates an application’s data model, user interface, and control logic into three distinct components (model, view and controller, respectively).&lt;br /&gt;
&lt;br /&gt;
==='''TDD'''===&lt;br /&gt;
In this project, we follow the Test-driven development (TDD) software development process, which means that we would first write a test that fails before you write new functional code.&lt;br /&gt;
&lt;br /&gt;
==='''DIY'''===&lt;br /&gt;
We are trying to reuse the existing functionalities in Expertiza, thus avoiding code duplication. Whenever possible, code modification based on the existing classes, controllers, or tables will be done instead of creating the new one.&lt;br /&gt;
&lt;br /&gt;
=='''Mockup Screen'''==&lt;br /&gt;
Below are the mock-up screens that explain “new account acreation” functionality in Expertiza. &lt;br /&gt;
*1.New user should click “request account” for requesting a new account, then redirect to the “request new ” page.&lt;br /&gt;
[[File:17a65.jpg]]&lt;br /&gt;
*2.After redirect to “request new ” page, new users should enter their information, includes role, name, e-mail and institution. If the institution that new users want to choose is not in the list, we can choose “others” option, then a textbox will appear. We can enter our new institution in this textbox. Finally, we can click “request” button to submit our request, and wait for being approved by administrator. &lt;br /&gt;
[[File:17a66.jpg]]&lt;br /&gt;
*3. If we login as administrator, we can see the screens below.&lt;br /&gt;
[[File:17a67.jpg]]&lt;br /&gt;
*4. If we click “show requests”, we can see this screen. The email address is clickable.&lt;br /&gt;
[[File:17a68.jpg]]&lt;br /&gt;
*5.If we click the email address, the email editor will pop out. Administrator can converse with requestor directly.&lt;br /&gt;
[[File:17a6a.jpg]]&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112107</id>
		<title>CSC/ECE 517 Fall 2017/E17A6 Fix account creation over web to work reasonably</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E17A6_Fix_account_creation_over_web_to_work_reasonably&amp;diff=112107"/>
		<updated>2017-11-07T01:50:20Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Use Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==  '''Introduction to Expertiza''' ==&lt;br /&gt;
Expertiza[https://expertiza.ncsu.edu/wiki/] is a project developed using Ruby on Rails[https://en.wikipedia.org/wiki/Ruby_on_Rails]. It provides features like peer review, team assignments and submission of projects. This can be achieved by submitting code base, URL of hosted code on remote server and Wiki submissions. It is an open source application and the code can be cloned from GitHub[https://en.wikipedia.org/wiki/GitHub]. This application provides an efficient way to manage assignments, grades and reviews. This makes the process easier and faster when the class strength is large.&lt;br /&gt;
== '''Introduction''' ==&lt;br /&gt;
=== '''Purpose''' ===&lt;br /&gt;
Expertiza provide the function for user to request an account, but the function is not perfect. The goal of our project is to improve this feature. It will enable Expertiza to handle the pending request for super-admin and add institution for user.&lt;br /&gt;
&lt;br /&gt;
=== '''Problem Definition''' ===&lt;br /&gt;
===='''New user request page'''====&lt;br /&gt;
*Currently, a new user can only choose institution from the dropdown. The new user should be able to add a new institution. &lt;br /&gt;
*A place where a new user to write a brief introduction is needed in this page.&lt;br /&gt;
*Also, in models/requested_user.rb, there are some validations, such as validate email address. It will be better to update the flash message on the view when validation fails.&lt;br /&gt;
===='''Super-admin and admin are able to approve or decline new user requests. '''====&lt;br /&gt;
*Currently, you have to go to /users/list_pending_requested this url to access a list of pending requests. It will be better to add an option in “Administration &amp;gt; Show…” menu &lt;br /&gt;
*Make “Email Address” column in /users/list_pending_requested page clickable. So that super-admin or admin could converse with requesters by clicking email addresses directly.&lt;br /&gt;
===='''After approving'''====&lt;br /&gt;
*After super-admin or admin approves the request, make sure the record does not disappear on the page. And there should be an email send to email address offered by requester.&lt;br /&gt;
&lt;br /&gt;
== '''Requirements''' ==&lt;br /&gt;
*Modify the test of request new user method. &lt;br /&gt;
*Add a new option for the drop-down bar of institution in the new user request page.&lt;br /&gt;
*Add a new textarea in the new user request page, to input a new institution and introduction.&lt;br /&gt;
*Add validation for new institution new institutions and introductions.&lt;br /&gt;
*Add flash message for requested_user.rb.&lt;br /&gt;
*Add a new button on the layout.&lt;br /&gt;
*Modify the layout of /users/list_pending_requested page.&lt;br /&gt;
*Enable the system will send an email after the request is processed.&lt;br /&gt;
&lt;br /&gt;
=='''Database Design'''==&lt;br /&gt;
[[File:17a61.JPG]]&lt;br /&gt;
*The above tables is the original table for this project, however it lacks a column for introduction. So we need to add a new column for request_user table. The new table will be shown below.&lt;br /&gt;
[[File:17a62.JPG]]&lt;br /&gt;
&lt;br /&gt;
=='''Use Cases'''==&lt;br /&gt;
[[File:17a63.jpg]]&lt;br /&gt;
*Name: Instructor or Teaching Assistant request a new account&lt;br /&gt;
*Actor: Instructor or Teaching Assistant&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: None&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Click on “Request account”.&lt;br /&gt;
::2.Select a role.&lt;br /&gt;
::3.Fill in a user name.&lt;br /&gt;
::4.Fill in a full name.&lt;br /&gt;
::5.Fill in an email address.&lt;br /&gt;
::6.Select an institution, if the institution not in the list, skip to the alternative flow.&lt;br /&gt;
::7.Fill in the introduction field.&lt;br /&gt;
::8.Click on “Request”.&lt;br /&gt;
*Alternative Flow:&lt;br /&gt;
::1.If the institution not in the list, click on “Others”.&lt;br /&gt;
::2.Fill in the institution name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin view list of new account requests&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Log in to Expertiza.&lt;br /&gt;
::2.Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3.View the list of new account requests.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin accept a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Log in to Expertiza.&lt;br /&gt;
::2.Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3.Select a request.&lt;br /&gt;
::4.Click on “Accept”.&lt;br /&gt;
::5.Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin reject a new account request&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Log in to Expertiza&lt;br /&gt;
::2.Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3.Select a request.&lt;br /&gt;
::4.Click on “Reject”.&lt;br /&gt;
::5.Click on “Submit”.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Name: Admin or Super admin send an email to applicant&lt;br /&gt;
*Actor: Admin or Super admin&lt;br /&gt;
*Other Participants: None&lt;br /&gt;
*Precondition: Instructor or Teaching Assistant has requested a new account&lt;br /&gt;
*Primary Sequence:&lt;br /&gt;
::1.Log in to Expertiza&lt;br /&gt;
::2.Click on the link “/users/list_pending_requested”.&lt;br /&gt;
::3.Select a request.&lt;br /&gt;
::4.Click on the email address.&lt;br /&gt;
::5.Write the email.&lt;br /&gt;
*Alternative Flow: None&lt;br /&gt;
&lt;br /&gt;
=='''Design Pattern'''==&lt;br /&gt;
==='''MVC'''===&lt;br /&gt;
The project is implemented in Ruby on Rails that uses MVC architecture. It separates an application’s data model, user interface, and control logic into three distinct components (model, view and controller, respectively).&lt;br /&gt;
&lt;br /&gt;
==='''TDD'''===&lt;br /&gt;
In this project, we follow the Test-driven development (TDD) software development process, which means that we would first write a test that fails before you write new functional code.&lt;br /&gt;
&lt;br /&gt;
==='''DIY'''===&lt;br /&gt;
We are trying to reuse the existing functionalities in Expertiza, thus avoiding code duplication. Whenever possible, code modification based on the existing classes, controllers, or tables will be done instead of creating the new one.&lt;br /&gt;
&lt;br /&gt;
=='''Mockup Screen'''==&lt;br /&gt;
Below are the mock-up screens that explain “new account acreation” functionality in Expertiza. &lt;br /&gt;
*1.New user should click “request account” for requesting a new account, then redirect to the “request new ” page.&lt;br /&gt;
[[File:17a65.jpg]]&lt;br /&gt;
*2.After redirect to “request new ” page, new users should enter their information, includes role, name, e-mail and institution. If the institution that new users want to choose is not in the list, we can choose “others” option, then a textbox will appear. We can enter our new institution in this textbox. Finally, we can click “request” button to submit our request, and wait for being approved by administrator. &lt;br /&gt;
[[File:17a66.jpg]]&lt;br /&gt;
*3. If we login as administrator, we can see the screens below.&lt;br /&gt;
[[File:17a67.jpg]]&lt;br /&gt;
*4. If we click “show requests”, we can see this screen. The email address is clickable.&lt;br /&gt;
[[File:17a68.jpg]]&lt;br /&gt;
*5.If we click the email address, the email editor will pop out. Administrator can converse with requestor directly.&lt;br /&gt;
[[File:17a6a.jpg]]&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=111754</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=111754"/>
		<updated>2017-11-03T12:52:54Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Resources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Test Cases ==&lt;br /&gt;
Because the project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model.&lt;br /&gt;
We wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first, with the  RSpec tool.&lt;br /&gt;
&lt;br /&gt;
The introduction video to our project&amp;lt;ref&amp;gt;Introduction video to our project https://www.youtube.com/watch?v=sJdmN-S2Voo&amp;amp;feature=youtu.be&amp;lt;/ref&amp;gt;&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our pull request&amp;lt;ref&amp;gt;Our pull request https://github.com/expertiza/expertiza/pull/1049&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109705</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109705"/>
		<updated>2017-10-27T04:14:42Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Test */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Test Cases ==&lt;br /&gt;
Because the project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model.&lt;br /&gt;
We wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first, with the  RSpec tool.&lt;br /&gt;
&lt;br /&gt;
The introduction video to our project&amp;lt;ref&amp;gt;Introduction video to our project https://www.youtube.com/watch?v=sJdmN-S2Voo&amp;amp;feature=youtu.be&amp;lt;/ref&amp;gt;&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109704</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109704"/>
		<updated>2017-10-27T04:10:55Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Test */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Test  ==&lt;br /&gt;
Because the project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model.&lt;br /&gt;
We wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first, with the  RSpec tool.&lt;br /&gt;
&lt;br /&gt;
The introduction video to our project&amp;lt;ref&amp;gt;Introduction video to our project https://www.youtube.com/watch?v=sJdmN-S2Voo&amp;amp;feature=youtu.be&amp;lt;/ref&amp;gt;&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109702</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109702"/>
		<updated>2017-10-27T04:10:15Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Test */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Test  ==&lt;br /&gt;
Because the project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model.&lt;br /&gt;
We wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first, with the  RSpec tool.&lt;br /&gt;
Introduction video to our project&amp;lt;ref&amp;gt;Introduction video to our project https://www.youtube.com/watch?v=sJdmN-S2Voo&amp;amp;feature=youtu.be&amp;lt;/ref&amp;gt;&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109701</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109701"/>
		<updated>2017-10-27T04:09:21Z</updated>

		<summary type="html">&lt;p&gt;Cshao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Test  ==&lt;br /&gt;
Because the project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model.&lt;br /&gt;
We wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first, with the  RSpec tool.&lt;br /&gt;
&amp;lt;ref&amp;gt;Introduction video to our project https://www.youtube.com/watch?v=sJdmN-S2Voo&amp;amp;feature=youtu.be&amp;lt;/ref&amp;gt;&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109698</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109698"/>
		<updated>2017-10-27T04:06:23Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Test */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Test  ==&lt;br /&gt;
Because the project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model.&lt;br /&gt;
We wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first, with the  RSpec tool.&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109697</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109697"/>
		<updated>2017-10-27T04:06:01Z</updated>

		<summary type="html">&lt;p&gt;Cshao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Test  ==&lt;br /&gt;
Because the project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model&lt;br /&gt;
We wrote 38 test cases for 24 methods in '''assignment_participant_spec.rb''' first, with the  RSpec tool.&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109694</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109694"/>
		<updated>2017-10-27T04:03:37Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Project Description */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in AssignmentParticipant model first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Test  ==&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109692</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109692"/>
		<updated>2017-10-27T04:02:48Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Test Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in AssignmentParticipant model first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109690</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109690"/>
		<updated>2017-10-27T04:01:13Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Test Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in AssignmentParticipant model first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
describe AssignmentParticipant do&lt;br /&gt;
  let(:response) { build(:response) }&lt;br /&gt;
  let(:team) { build(:assignment_team, id: 1) }&lt;br /&gt;
  let(:team2) { build(:assignment_team, id: 2) }&lt;br /&gt;
  let(:response_map) { build(:review_response_map, reviewer_id: 2, response: [response]) }&lt;br /&gt;
  let(:participant) { build(:participant, id: 1, assignment: assignment) }&lt;br /&gt;
  let(:participant2) { build(:participant, id: 2, grade: 100) }&lt;br /&gt;
  let(:assignment) { build(:assignment, id: 1) }&lt;br /&gt;
  let(:review_questionnaire) { build(:questionnaire, id: 1) }&lt;br /&gt;
  let(:question) { double('Question') }&lt;br /&gt;
  let(:quiz_questionaire) { build(:questionnaire, id: 2) }&lt;br /&gt;
  let(:student) { build(:student, name: &amp;quot;student2064&amp;quot;, fullname: &amp;quot;2064, student&amp;quot;, handle: &amp;quot;handle&amp;quot;) }&lt;br /&gt;
  let(:assignment_questionnaire) { build(:assignment_questionnaire) }&lt;br /&gt;
  let(:assignment_questionnaire2) { build(:assignment_questionnaire, used_in_round: 1) }&lt;br /&gt;
  let(:topic) { build(:topic) }&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    allow(assignment).to receive(:questionnaires).and_return([review_questionnaire])&lt;br /&gt;
    allow(participant).to receive(:team).and_return(team)&lt;br /&gt;
    allow(participant).to receive(:user).and_return(student)&lt;br /&gt;
    allow(ResponseMap).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
    allow(SignedUpTeam).to receive(:topic_id).with(any_args).and_return(1)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#dir_path' do&lt;br /&gt;
    it 'returns the directory path of current assignment' do&lt;br /&gt;
      expect(participant.dir_path).to eq &amp;quot;final_test&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#assign_quiz' do&lt;br /&gt;
    it 'creates a new QuizResponseMap record' do&lt;br /&gt;
      allow(QuizQuestionnaire).to receive(:find_by).with(instructor_id: 1).and_return(quiz_questionaire) # WHY CAN NOT DELETE THIS SENTENCE&lt;br /&gt;
      expect { participant.assign_quiz(participant, participant2, nil) }.to change { QuizResponseMap.count }.from(0).to(1)&lt;br /&gt;
      expect(participant.assign_quiz(participant, participant2, nil)).to be_an_instance_of(QuizResponseMap)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviewers' do&lt;br /&gt;
    it 'returns all the participants in this assignment who have reviewed the team where this participant belongs' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:where).with(any_args).and_return([response_map]) # differences with .with(parameter)&lt;br /&gt;
      allow(AssignmentParticipant).to receive(:find).with(any_args).and_return(participant2)&lt;br /&gt;
      expect(participant.reviewers).to eq([participant2])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_score' do&lt;br /&gt;
    it 'returns the review score' do&lt;br /&gt;
      # diao yong de method tai duo le,er qie bu zhi dao sha yi si&lt;br /&gt;
      allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
      allow(review_questionnaire).to receive(:questions).and_return(question)&lt;br /&gt;
      allow(Answer).to receive(:compute_scores).with([response], question).and_return(avg: 100)&lt;br /&gt;
      allow(review_questionnaire).to receive(:max_possible_score).and_return(100)&lt;br /&gt;
      expect(participant.review_score).to eq(100)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#scores' do&lt;br /&gt;
    context 'when assignment is not varying rubric by round and not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is varying rubric by round but not an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:merge_scores)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(false)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when assignment is not varying rubric by round but an microtask' do&lt;br /&gt;
      it 'calculates scores that this participant has been given' do&lt;br /&gt;
        expect(participant).to receive(:assignment_questionnaires)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        allow(assignment).to receive(:varying_rubrics_by_round?).and_return(false)&lt;br /&gt;
        allow(assignment).to receive(:is_microtask?).and_return(true)&lt;br /&gt;
        expect(participant).to receive(:topic_total_scores)&lt;br /&gt;
        expect(assignment).to receive(:compute_total_score)&lt;br /&gt;
        expect(participant).to receive(:caculate_scores)&lt;br /&gt;
        participant.scores(question)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  # included method&lt;br /&gt;
  describe '#assignment_questionnaires' do&lt;br /&gt;
    context 'when the round of questionnaire is nil' do&lt;br /&gt;
      it 'record the result as review scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).with(any_args).and_return(assignment_questionnaire)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the round of questionnaire is not nil' do&lt;br /&gt;
      it 'record the result as review#{n} scores' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        question_hash = {review1: question}&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        allow(AssignmentQuestionnaire).to receive(:find_by).and_return(assignment_questionnaire2)&lt;br /&gt;
        allow(review_questionnaire).to receive(:get_assessments_round_for).with(any_args).and_return([response])&lt;br /&gt;
        allow(Answer).to receive(:compute_scores).with(any_args).and_return(score_map)&lt;br /&gt;
        participant.assignment_questionnaires(question_hash, scores)&lt;br /&gt;
        expect(scores[:review1][:assessments]).to eq([response])&lt;br /&gt;
        expect(scores[:review1][:scores]).to eq(score_map)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#merge_scores' do&lt;br /&gt;
    context 'when all of the review_n are nil' do&lt;br /&gt;
      it 'set max, min, avg of review score as 0' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when the review_n is not nil' do&lt;br /&gt;
      it 'merge the score of review_n to the score of review' do&lt;br /&gt;
        score_map = {max: 100, min: 100, avg: 100}&lt;br /&gt;
        scores = {review1: {scores: score_map, assessments: [response]}}&lt;br /&gt;
        allow(assignment).to receive(:num_review_rounds).and_return(1)&lt;br /&gt;
        participant.merge_scores(scores)&lt;br /&gt;
        expect(scores[:review][:scores][:max]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
        expect(scores[:review][:scores][:min]).to eq(100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#topic_total_scores' do&lt;br /&gt;
    it 'set total_score and max_pts_available of score when topic is not nil' do&lt;br /&gt;
      scores = {total_score: 100}&lt;br /&gt;
      allow(SignUpTopic).to receive(:find_by).with(any_args).and_return(topic)&lt;br /&gt;
      participant.topic_total_scores(scores)&lt;br /&gt;
      expect(scores[:total_score]).to eq(0)&lt;br /&gt;
      expect(scores[:max_pts_available]).to eq(0)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#caculate_scores' do&lt;br /&gt;
    context 'when the participant has the grade' do&lt;br /&gt;
      it 'his total scores equals his grade' do&lt;br /&gt;
        scores = {}&lt;br /&gt;
        expect(participant2.caculate_scores(scores)).to eq(100.0)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score more than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score 100' do&lt;br /&gt;
        scores = {total_score: 110}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 100)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    context 'when the participant has the grade and the total score less than 100' do&lt;br /&gt;
      it 'return the score of a given participant with total score' do&lt;br /&gt;
        scores = {total_score: 90}&lt;br /&gt;
        expect(participant.caculate_scores(scores)).to eq(total_score: 90)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#copy' do&lt;br /&gt;
    it 'copies assignment participants to a certain course' do&lt;br /&gt;
      expect(participant.copy(517)).to be_an_instance_of(CourseParticipant)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#feedback' do&lt;br /&gt;
    it 'returns corrsponding author feedback responses given by current participant' do&lt;br /&gt;
      expect(participant.feedback).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by current team' do&lt;br /&gt;
      expect(participant.reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#reviews_by_reviewer' do&lt;br /&gt;
    it 'returns corrsponding peer review responses given by certain reviewer' do&lt;br /&gt;
      allow(ReviewResponseMap).to receive(:get_reviewer_assessments_for).with(team, participant2).and_return([response])&lt;br /&gt;
      expect(participant.reviews_by_reviewer(participant2)).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#quizzes_taken' do&lt;br /&gt;
    it 'returns corrsponding quiz responses given by current participant' do&lt;br /&gt;
      expect(participant.quizzes_taken).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#metareviews' do&lt;br /&gt;
    it 'returns corrsponding metareview responses given by current participant' do&lt;br /&gt;
      expect(participant.metareviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#teammate_reviews' do&lt;br /&gt;
    it 'returns corrsponding teammate review responses given by current participant' do&lt;br /&gt;
      expect(participant.teammate_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#bookmark_reviews' do&lt;br /&gt;
    it 'returns corrsponding bookmark review responses given by current participant' do&lt;br /&gt;
      expect(participant.bookmark_reviews).to eq([response])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#files' do&lt;br /&gt;
    context 'when there is not subdirectory in current directory' do&lt;br /&gt;
      it 'returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/k.rb&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when there is subdirectory in current directory' do&lt;br /&gt;
      it 'recursively returns all files in current directory' do&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/*&amp;quot;).and_return([&amp;quot;a/b&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b&amp;quot;).and_return(true)&lt;br /&gt;
        allow(Dir).to receive(:[]).with(&amp;quot;a/b/*&amp;quot;).and_return([&amp;quot;a/b/k.rb&amp;quot;])&lt;br /&gt;
        allow(File).to receive(:directory?).with(&amp;quot;a/b/k.rb&amp;quot;).and_return(false)&lt;br /&gt;
        expect(participant.files(&amp;quot;a&amp;quot;)).to eq([&amp;quot;a/b/k.rb&amp;quot;, &amp;quot;a/b&amp;quot;])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;.import&amp;quot; do&lt;br /&gt;
    context 'when record is empty' do&lt;br /&gt;
      it 'raises an ArgumentError' do&lt;br /&gt;
        row = []&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
        expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
        expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;No user id has been specified.&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when no user is found by offered username' do&lt;br /&gt;
      context 'when the record has less than 4 items' do&lt;br /&gt;
        it 'raises an ArgumentError' do&lt;br /&gt;
          row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;]&lt;br /&gt;
          allow(AssignmentParticipant).&lt;br /&gt;
            to receive(:check_info_and_create).with(any_args).and_raise(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
          expect(AssignmentParticipant).to receive(:check_info_and_create)&lt;br /&gt;
          expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error(&amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'when the record has more than 4 items' do&lt;br /&gt;
        context 'when certain assignment cannot be found' do&lt;br /&gt;
          it 'creates a new user based on import information and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(nil)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.&lt;br /&gt;
              to raise_error(&amp;quot;The assignment with id \&amp;quot;2\&amp;quot; was not found.&amp;quot;).and change { User.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        context 'when certain assignment can be found and assignment participant does not exists' do&lt;br /&gt;
          it 'creates a new user, new participant and raises an ImportError' do&lt;br /&gt;
            row = [&amp;quot;user_name&amp;quot;, &amp;quot;user_fullname&amp;quot;, &amp;quot;name@email.com&amp;quot;, &amp;quot;user_role_name&amp;quot;, &amp;quot;user_parent_name&amp;quot;]&lt;br /&gt;
            session = {user: participant}&lt;br /&gt;
            allow(User).to receive(:find_by_name).with(any_args).and_return(nil)&lt;br /&gt;
            allow(Assignment).to receive(:find).with(2).and_return(assignment)&lt;br /&gt;
            allow(AssignmentParticipant).to receive(:exists?).and_return(false)&lt;br /&gt;
            expect { AssignmentParticipant.import(row, nil, session, 2) }.to change { User.count }.by(1).and change { AssignmentParticipant.count }.by(1)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '.export' do&lt;br /&gt;
    it 'exports all participants in current assignment' do&lt;br /&gt;
      csv = []&lt;br /&gt;
      expect(AssignmentParticipant).to receive_message_chain(:where, :find_each).with(any_args).and_yield(participant)&lt;br /&gt;
      expect(AssignmentParticipant.export(csv, 1, any_args)).&lt;br /&gt;
        to eq([[&amp;quot;student2064&amp;quot;, &amp;quot;2064, student&amp;quot;, &amp;quot;expertiza@mailinator.com&amp;quot;, &amp;quot;Student&amp;quot;, &amp;quot;instructor6&amp;quot;, true, true, true, &amp;quot;handle&amp;quot;]])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#set_handle' do&lt;br /&gt;
    context 'when the user of current participant does not have handle' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        allow(student).to receive_message_chain(:handle, :nil?).and_return(true)&lt;br /&gt;
        allow(student).to receive(:handle).and_return(&amp;quot;&amp;quot;)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment exists participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the name of current participant' do&lt;br /&gt;
        allow(AssignmentParticipant).to receive(:exists?).with(any_args).and_return(true)&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;student2064&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when current assignment does not have participants with same handle as the one of current user' do&lt;br /&gt;
      it 'sets the user name as the handle of current participant' do&lt;br /&gt;
        participant.set_handle&lt;br /&gt;
        expect(participant.handle).to eq(&amp;quot;handle&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#review_file_path' do&lt;br /&gt;
    it 'returns the file path for reviewer to upload files during peer review' do&lt;br /&gt;
      allow(ResponseMap).to receive(:find).with(any_args).and_return(response_map)&lt;br /&gt;
      allow(TeamsUser).to receive_message_chain(:find_by, :user_id).with(any_args).and_return(1)&lt;br /&gt;
      allow(Participant).to receive(:find_by).with(any_args).and_return(participant)&lt;br /&gt;
      file_path = Rails.root.to_s + &amp;quot;/pg_data/instructor6/csc517/test/final_test/0_review/1&amp;quot;&lt;br /&gt;
      expect(participant.review_file_path(1)).to eq(file_path)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#current_stage' do&lt;br /&gt;
    it 'returns stage of current assignment' do&lt;br /&gt;
      allow(assignment).to receive(:get_current_stage).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
      expect(participant.current_stage).to eq(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe '#stage_deadline' do&lt;br /&gt;
    context 'when stage of current assignment is not Finished' do&lt;br /&gt;
      it 'returns current stage' do&lt;br /&gt;
        allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
        expect(participant.stage_deadline).to eq(&amp;quot;Unknow&amp;quot;)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    context 'when stage of current assignment not Finished' do&lt;br /&gt;
      context 'current assignment is not a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current assignment' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(false)&lt;br /&gt;
          allow(assignment).to receive_message_chain(:due_dates, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      context 'current assignment is a staggered deadline assignment' do&lt;br /&gt;
        it 'returns the due date of current topic' do&lt;br /&gt;
          allow(assignment).to receive(:stage_deadline).with(1).and_return(&amp;quot;Finished&amp;quot;)&lt;br /&gt;
          allow(assignment).to receive(:staggered_deadline?).and_return(true)&lt;br /&gt;
          allow(TopicDueDate).to receive_message_chain(:find_by, :last, :due_at).and_return(1)&lt;br /&gt;
          expect(participant.stage_deadline).to eq(&amp;quot;1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109687</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109687"/>
		<updated>2017-10-27T04:00:10Z</updated>

		<summary type="html">&lt;p&gt;Cshao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at using TFD(Test First Development) to refactor the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc.&lt;br /&gt;
&lt;br /&gt;
We used the TDF(Test First Development) method to refactor the AssignmentParticipant model. With the  RSpec tool, we wrote 38 test cases for 24 methods in AssignmentParticipant model first. After finishing these test cases, we executed them, and most of them failed. And then we refactored the methods, '''scores''', '''files''', '''self.import''', '''find_by''', '''where.first''', and executed the test cases again, finally they all passed.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109666</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109666"/>
		<updated>2017-10-27T03:45:12Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Self.import  method===&lt;br /&gt;
The self.import method of AssignmentParticipant model is exactly the same as '''course_participant.rb, L21''', so we move it to a module named Class_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and CourseParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Class_method&lt;br /&gt;
&lt;br /&gt;
  def self.import(row, _row_header = nil, session, id)&lt;br /&gt;
    user = AssignmentParticipant.check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ImportError, &amp;quot;The assignment with id \&amp;quot;&amp;quot; + id.to_s + &amp;quot;\&amp;quot; was not found.&amp;quot; if Assignment.find(id).nil?&lt;br /&gt;
    unless AssignmentParticipant.exists?(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part = AssignmentParticipant.create(user_id: user.id, parent_id: id)&lt;br /&gt;
      new_part.set_handle&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* module Class_method&lt;br /&gt;
  def check_info_and_create(row, _row_header = nil, session)&lt;br /&gt;
    raise ArgumentError, &amp;quot;No user id has been specified.&amp;quot; if row.empty?&lt;br /&gt;
    user = User.find_by(name: row[0])&lt;br /&gt;
    if user.nil?&lt;br /&gt;
      raise ArgumentError, &amp;quot;The record containing #{row[0]} does not have enough items.&amp;quot; if row.length &amp;lt; 4&lt;br /&gt;
      attributes = ImportFileHelper.define_attributes(row)&lt;br /&gt;
      user = ImportFileHelper.create_new_user(attributes, session)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109660</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109660"/>
		<updated>2017-10-27T03:32:11Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109659</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109659"/>
		<updated>2017-10-27T03:30:31Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109658</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109658"/>
		<updated>2017-10-27T03:29:58Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Find_by methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Find_by method===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109657</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109657"/>
		<updated>2017-10-27T03:29:28Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109656</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109656"/>
		<updated>2017-10-27T03:29:03Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_metho&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109655</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109655"/>
		<updated>2017-10-27T03:28:47Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model is exactly the same as '''assignment_team.rb, L103''', so we move it to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below two lines are added to the AssignmentParticipant model and AssignmentTeam model.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_metho&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109654</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109654"/>
		<updated>2017-10-27T03:19:59Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model has been moved to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_metho&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109653</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109653"/>
		<updated>2017-10-27T03:19:22Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model has been moved to a module named Instance_method in '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_metho&lt;br /&gt;
&lt;br /&gt;
module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109652</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109652"/>
		<updated>2017-10-27T03:18:53Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model has been moved to a module named Instance_method in the lib directory '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
* module Instance_metho&lt;br /&gt;
&lt;br /&gt;
module Instance_method&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = []&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each {|f| files &amp;lt;&amp;lt; f }&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109651</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109651"/>
		<updated>2017-10-27T03:16:40Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Files method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model have been moved to the lib directory '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
require 'TFD1770_refactor'&lt;br /&gt;
include Instance_method&lt;br /&gt;
&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109650</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109650"/>
		<updated>2017-10-27T03:15:10Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* File and directory methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Files method===&lt;br /&gt;
The files method of AssignmentParticipant model have been moved to the lib directory '''lib/TFD1770_refactor.rb'''.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109649</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109649"/>
		<updated>2017-10-27T03:11:39Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Review methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Find_by methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109648</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109648"/>
		<updated>2017-10-27T03:10:46Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Review methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
Use '''find_by''' instead of dynamic method&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use '''find_by''' instead of where.first&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109647</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109647"/>
		<updated>2017-10-27T03:03:27Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Review methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by(name:row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109646</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109646"/>
		<updated>2017-10-27T02:56:16Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Review methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L34&lt;br /&gt;
quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L134&lt;br /&gt;
topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
&lt;br /&gt;
* TFD1770_refactor.rb L20&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
*  assignment_particpant.rb L267&lt;br /&gt;
first_user_id = TeamsUser.where(team_id: response_map.reviewee_id).first.user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L267&lt;br /&gt;
participant = Participant.where(parent_id: response_map.reviewed_object_id, user_id: first_user_id).first&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
*  assignment_particpant.rb L258&lt;br /&gt;
first_user_id = TeamsUser.find_by(team_id: response_map.reviewee_id).user_id&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L259&lt;br /&gt;
participant = Participant.find_by(parent_id: response_map.reviewed_object_id, user_id: first_user_id)&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109642</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109642"/>
		<updated>2017-10-27T02:48:22Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Review methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
*  assignment_particpant.rb L32&lt;br /&gt;
quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L113&lt;br /&gt;
topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
&lt;br /&gt;
* assignment_particpant.rb L196&lt;br /&gt;
user = User.find_by_name(row[0])&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109641</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109641"/>
		<updated>2017-10-27T02:43:47Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Review methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  * def assign_quiz(contributor, reviewer, _topic = nil)&lt;br /&gt;
    quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    QuizResponseMap.create(reviewed_object_id: quiz.try(:id), reviewee_id: contributor.id, reviewer_id: reviewer.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||  &lt;br /&gt;
* def assign_quiz(contributor, reviewer, _topic = nil)&lt;br /&gt;
    quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
    QuizResponseMap.create(reviewed_object_id: quiz.try(:id), reviewee_id: contributor.id, reviewer_id: reviewer.id)&lt;br /&gt;
  end&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109640</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109640"/>
		<updated>2017-10-27T02:42:59Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Review methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  * def assign_quiz(contributor, reviewer, _topic = nil)&lt;br /&gt;
    quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    QuizResponseMap.create(reviewed_object_id: quiz.try(:id), reviewee_id: contributor.id, reviewer_id: reviewer.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||  * def assign_quiz(contributor, reviewer, _topic = nil)&lt;br /&gt;
    quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
    QuizResponseMap.create(reviewed_object_id: quiz.try(:id), reviewee_id: contributor.id, reviewer_id: reviewer.id)&lt;br /&gt;
  end&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109639</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109639"/>
		<updated>2017-10-27T02:41:20Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Review methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def assign_quiz(contributor, reviewer, _topic = nil)&lt;br /&gt;
    quiz = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    QuizResponseMap.create(reviewed_object_id: quiz.try(:id), reviewee_id: contributor.id, reviewer_id: reviewer.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||  def assign_quiz(contributor, reviewer, _topic = nil)&lt;br /&gt;
    quiz = QuizQuestionnaire.find_by(instructor_id: contributor.id)&lt;br /&gt;
    QuizResponseMap.create(reviewed_object_id: quiz.try(:id), reviewee_id: contributor.id, reviewer_id: reviewer.id)&lt;br /&gt;
  end&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109637</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109637"/>
		<updated>2017-10-27T02:38:07Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Remove unused methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109636</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109636"/>
		<updated>2017-10-27T02:37:43Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* set_handle method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109635</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109635"/>
		<updated>2017-10-27T02:34:23Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Scores method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = {}&lt;br /&gt;
      scores[review_sym][:assessments] = []&lt;br /&gt;
      scores[review_sym][:scores] = {}&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
        scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
        if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
          scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
          scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      unless topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109633</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109633"/>
		<updated>2017-10-27T02:32:22Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Scores method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
    # merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    merge_scores(scores) if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    topic_total_scores(scores) if self.assignment.is_microtask?&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    # quiz_responses = []&lt;br /&gt;
    # quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    # quiz_response_mappings.each do |qmapping|&lt;br /&gt;
    #   quiz_responses &amp;lt;&amp;lt; qmapping.response if qmapping.response&lt;br /&gt;
    # end&lt;br /&gt;
    # scores[:quiz] = Hash.new&lt;br /&gt;
    # scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    # scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    # scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    caculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by(assignment_id: self.assignment.id, questionnaire_id: questionnaire.id).used_in_round&lt;br /&gt;
      # create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      questionnaire_symbol = if round.nil?&lt;br /&gt;
                               questionnaire.symbol&lt;br /&gt;
                             else&lt;br /&gt;
                               (questionnaire.symbol.to_s + round.to_s).to_sym&lt;br /&gt;
                             end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol][:assessments] = if round.nil?&lt;br /&gt;
                                                     questionnaire.get_assessments_for(self)&lt;br /&gt;
                                                   else&lt;br /&gt;
                                                     questionnaire.get_assessments_round_for(self, round)&lt;br /&gt;
                                                   end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
    scores[review_sym] = {}&lt;br /&gt;
    scores[review_sym][:assessments] = []&lt;br /&gt;
    scores[review_sym][:scores] = {max: -999_999_999, min: 999_999_999, avg: 0}&lt;br /&gt;
    total_score = 0&lt;br /&gt;
    for i in 1..self.assignment.num_review_rounds&lt;br /&gt;
      round_sym = (&amp;quot;review&amp;quot; + i.to_s).to_sym&lt;br /&gt;
      if scores[round_sym].nil? || scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].empty?&lt;br /&gt;
        next&lt;br /&gt;
      end&lt;br /&gt;
      length_of_assessments = scores[round_sym][:assessments].length.to_f&lt;br /&gt;
      scores[review_sym][:assessments] += scores[round_sym][:assessments]&lt;br /&gt;
      if !scores[round_sym][:scores][:max].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:max] &amp;lt; scores[round_sym][:scores][:max]&lt;br /&gt;
        scores[review_sym][:scores][:max] = scores[round_sym][:scores][:max]&lt;br /&gt;
      end&lt;br /&gt;
      if !scores[round_sym][:scores][:min].nil? &amp;amp;&amp;amp; scores[review_sym][:scores][:min] &amp;gt; scores[round_sym][:scores][:min]&lt;br /&gt;
        scores[review_sym][:scores][:min] = scores[round_sym][:scores][:min]&lt;br /&gt;
      end&lt;br /&gt;
      unless scores[round_sym][:scores][:avg].nil?&lt;br /&gt;
        total_score += scores[round_sym][:scores][:avg] * length_of_assessments&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    if scores[review_sym][:scores][:max] == -999_999_999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999_999_999&lt;br /&gt;
      scores[review_sym][:scores][:max] = 0&lt;br /&gt;
      scores[review_sym][:scores][:min] = 0&lt;br /&gt;
    end&lt;br /&gt;
    scores[review_sym][:scores][:avg] = total_score / scores[review_sym][:assessments].length.to_f&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
*  topic_total_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def topic_total_scores(scores)&lt;br /&gt;
    topic = SignUpTopic.find_by(assignment_id: self.assignment.id)&lt;br /&gt;
    unless topic.nil?&lt;br /&gt;
      scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
      scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def caculate_scores(scores)&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      scores[:total_score] = 100 if scores[:total_score] &amp;gt; 100&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109626</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109626"/>
		<updated>2017-10-27T02:23:58Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Scores method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''',  '''topic_total_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    merge_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    calculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def calculate_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109412</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109412"/>
		<updated>2017-10-26T15:50:45Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Test First Development */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test Cases==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    merge_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    calculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def calculate_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109411</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109411"/>
		<updated>2017-10-26T15:38:23Z</updated>

		<summary type="html">&lt;p&gt;Cshao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
==Test First Development==&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    merge_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    calculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def calculate_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109410</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109410"/>
		<updated>2017-10-26T15:34:53Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* 1 Introduction to Expertiza */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    merge_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    calculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def calculate_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109409</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109409"/>
		<updated>2017-10-26T15:34:43Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* 2 Why refactoring? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==1 Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    merge_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    calculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def calculate_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109408</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109408"/>
		<updated>2017-10-26T15:34:27Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Why refactoring? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==1 Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==2 Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    merge_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    calculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def calculate_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109407</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109407"/>
		<updated>2017-10-26T15:34:07Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Introduction to Expertiza */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==1 Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    merge_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    calculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def calculate_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109406</id>
		<title>CSC/ECE 517 Fall 2017/E1770 Refactor assignment participant.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2017/E1770_Refactor_assignment_participant.rb&amp;diff=109406"/>
		<updated>2017-10-26T15:32:56Z</updated>

		<summary type="html">&lt;p&gt;Cshao: /* Why Test-driven development? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''E1770. [Test First Development] Refactor assignment_participant.rb'''&amp;lt;ref&amp;gt;Project Description document https://docs.google.com/document/d/1rdolBAHxVGI9I0N-cT866AqnfORM2L1_m_bo2gRYRrI/edit#heading=h.s18ldps2kz5e&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page provides a brief description of the '''Expertiza''' project. The project is aimed at refactoring the AssignmentParticipant model which is subclass of Participant model. This model is used to maintain the list of students/users participating in a given assignment. For any new or existing assignments, this model manages the entire list of users assigned to that particular assignment. It primarily includes method for scores calculations, assignment submission paths, reviews, etc. As part of this project, some of the methods have been removed which were not being used anywhere, some have been moved to their appropriate helper module and some have been refactored into smaller ones.&lt;br /&gt;
&lt;br /&gt;
==Introduction to Expertiza==&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is a peer review based system which provides incremental learning from the class. This project has been developed together by faculty and students using [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create, edit and delete assignments, create new assignment topics, assign them to a particular class or selected students, have students work on teams and then review each other's assignments at the end. For the students, they can signup for topics, form teams, and submit their projects and assignments. &lt;br /&gt;
Students then review the work done by other students and give suggestions to improve. Teams after reviews are allotted scores and they can refer to the peer comments to further improve their work. It also supports submission of different file types for assignments, including the URLs and wiki pages.&lt;br /&gt;
&lt;br /&gt;
==Why refactoring?==&lt;br /&gt;
'''Code Refactoring'''&amp;lt;ref&amp;gt;Refactoring https://en.wikipedia.org/wiki/Code_refactoring&amp;lt;/ref&amp;gt; is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. &lt;br /&gt;
&lt;br /&gt;
Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements. Many development environments provide automated support for performing the mechanical aspects of these basic refactorings. If done extremely well, code refactoring may also resolve hidden, dormant, or undiscovered bugs or vulnerabilities in the system by simplifying the underlying logic and eliminating unnecessary levels of complexity. If done poorly it may fail the requirement that external functionality not be changed, introduce new bugs, or both.&lt;br /&gt;
&lt;br /&gt;
==Why Test-driven development?==&lt;br /&gt;
'''Test-driven development (TDD)'''&amp;lt;ref&amp;gt;Test-driven development (TDD) https://en.wikipedia.org/wiki/Test-driven_development&amp;lt;/ref&amp;gt; is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements. The followings are several benefits of Test-driven development (TDD).&lt;br /&gt;
&lt;br /&gt;
* Maintainable, Flexible, Easily Extensible.&lt;br /&gt;
* Unparalleled Test Coverage &amp;amp; Streamlined Codebase.&lt;br /&gt;
* Clean Interface.&lt;br /&gt;
* Refactoring Encourages Improvements.&lt;br /&gt;
* Executable Documentation.&lt;br /&gt;
&lt;br /&gt;
==Introduction to  RSpec==&lt;br /&gt;
'''RSpec'''&amp;lt;ref&amp;gt;RSpec https://en.wikipedia.org/wiki/RSpec&amp;lt;/ref&amp;gt; is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code. It is a behavior-driven development (BDD) framework which is extensively used in the production applications. The basic idea behind this concept is that of Test Driven Development(TDD) where the tests are written first and the development is based on writing just enough code that will fulfill those tests followed by refactoring. It contains its own mocking framework that is fully integrated into the framework based upon JMock. The simplicity in the RSpec syntax makes it one of the popular testing tools for Ruby applications. The RSpec tool can be used by installing the rspec gem which consists of 3 other gems namely rspec-core , rspec-expectation and rspec-mock.&lt;br /&gt;
&lt;br /&gt;
== Project Description ==&lt;br /&gt;
Refactor '''AssignmentParticipant''' model which is a subclass of '''Participant''' model.&lt;br /&gt;
The following tasks have been performed as per the requirements.&lt;br /&gt;
&lt;br /&gt;
* Refactor scores method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Split into several simpler methods and assign reasonable names.&lt;br /&gt;
** Extract duplicated code into separate methods.&lt;br /&gt;
** Replace the conditional with the relevant method calls.&lt;br /&gt;
&lt;br /&gt;
* Method files is exactly the same as assignment_team.rb L103.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Method self.import is exact the same as course_participant.rb L21.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
** Solve the duplication, extract method to a new file or delete useless one.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of dynamic method.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
* Use find_by instead of where.first.&lt;br /&gt;
** Write failing tests first.&lt;br /&gt;
&lt;br /&gt;
== Refactoring ==&lt;br /&gt;
===Scores method===&lt;br /&gt;
The method '''scores''' has been converted to smaller methods '''scores''', '''assignment_questionnaires''',  '''merge_scores''', '''calculate_scores'''. It is a good practice to keep the methods not extremely long as they tend to complicate the functionality and the readability.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
               scores[review_sym][:scores][:max] = 0&lt;br /&gt;
               scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
    scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
||&lt;br /&gt;
* scores(questions) method&lt;br /&gt;
&lt;br /&gt;
  def scores(questions)&lt;br /&gt;
    scores = {}&lt;br /&gt;
    scores[:participant] = self&lt;br /&gt;
&lt;br /&gt;
    assignment_questionnaires(questions, scores)&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = self.assignment.compute_total_score(scores)&lt;br /&gt;
&lt;br /&gt;
    merge_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    # In the event that this is a microtask, we need to scale the score accordingly and record the total possible points&lt;br /&gt;
    # PS: I don't like the fact that we are doing this here but it is difficult to make it work anywhere else&lt;br /&gt;
    if assignment.is_microtask?&lt;br /&gt;
      topic = SignUpTopic.find_by_assignment_id(assignment.id)&lt;br /&gt;
      if !topic.nil?&lt;br /&gt;
        scores[:total_score] *= (topic.micropayment.to_f / 100.to_f)&lt;br /&gt;
        scores[:max_pts_available] = topic.micropayment&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # for all quiz questionnaires (quizzes) taken by the participant&lt;br /&gt;
    quiz_responses = Array.new&lt;br /&gt;
    quiz_response_mappings = QuizResponseMap.where(reviewer_id: self.id)&lt;br /&gt;
    quiz_response_mappings.each do |qmapping|&lt;br /&gt;
      if (qmapping.response)&lt;br /&gt;
        quiz_responses &amp;lt;&amp;lt; qmapping.response&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    #scores[:quiz] = Hash.new&lt;br /&gt;
    #scores[:quiz][:assessments] = quiz_responses&lt;br /&gt;
    #scores[:quiz][:scores] = Answer.compute_quiz_scores(scores[:quiz][:assessments])&lt;br /&gt;
&lt;br /&gt;
    scores[:total_score] = assignment.compute_total_score(scores)&lt;br /&gt;
    #scores[:total_score] += compute_quiz_scores(scores)&lt;br /&gt;
&lt;br /&gt;
    calculate_scores(scores)&lt;br /&gt;
  end&lt;br /&gt;
* assignment_questionnaires(questions, scores) method&lt;br /&gt;
&lt;br /&gt;
  def assignment_questionnaires(questions, scores)&lt;br /&gt;
    self.assignment.questionnaires.each do |questionnaire|&lt;br /&gt;
      round = AssignmentQuestionnaire.find_by_assignment_id_and_questionnaire_id(self.assignment.id, questionnaire.id).used_in_round&lt;br /&gt;
      #create symbol for &amp;quot;varying rubrics&amp;quot; feature -Yang&lt;br /&gt;
      if(round!=nil)&lt;br /&gt;
        questionnaire_symbol = (questionnaire.symbol.to_s+round.to_s).to_sym&lt;br /&gt;
      else&lt;br /&gt;
        questionnaire_symbol = questionnaire.symbol&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[questionnaire_symbol] = {}&lt;br /&gt;
&lt;br /&gt;
      if round==nil&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_for(self)&lt;br /&gt;
      else&lt;br /&gt;
        scores[questionnaire_symbol][:assessments] = questionnaire.get_assessments_round_for(self,round)&lt;br /&gt;
      end&lt;br /&gt;
      scores[questionnaire_symbol][:scores] = Answer.compute_scores(scores[questionnaire_symbol][:assessments], questions[questionnaire_symbol])&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* merge_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def merge_scores(scores)&lt;br /&gt;
    #merge scores[review#] (for each round) to score[review]  -Yang&lt;br /&gt;
    if self.assignment.varying_rubrics_by_round?&lt;br /&gt;
      review_sym = &amp;quot;review&amp;quot;.to_sym&lt;br /&gt;
      scores[review_sym] = Hash.new&lt;br /&gt;
      scores[review_sym][:assessments] = Array.new&lt;br /&gt;
      scores[review_sym][:scores] = Hash.new&lt;br /&gt;
      scores[review_sym][:scores][:max] = -999999999&lt;br /&gt;
      scores[review_sym][:scores][:min] = 999999999&lt;br /&gt;
      scores[review_sym][:scores][:avg] = 0&lt;br /&gt;
      total_score = 0&lt;br /&gt;
      for i in 1..self.assignment.get_review_rounds&lt;br /&gt;
        round_sym = (&amp;quot;review&amp;quot;+i.to_s).to_sym&lt;br /&gt;
        if scores[round_sym][:assessments].nil? || scores[round_sym][:assessments].length==0&lt;br /&gt;
          next&lt;br /&gt;
        end&lt;br /&gt;
        length_of_assessments=scores[round_sym][:assessments].length.to_f&lt;br /&gt;
&lt;br /&gt;
        scores[review_sym][:assessments]+=scores[round_sym][:assessments]&lt;br /&gt;
&lt;br /&gt;
        if(scores[round_sym][:scores][:max]!=nil &amp;amp;&amp;amp; scores[review_sym][:scores][:max]&amp;lt;scores[round_sym][:scores][:max])&lt;br /&gt;
          scores[review_sym][:scores][:max]= scores[round_sym][:scores][:max]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:min]!= nil &amp;amp;&amp;amp; scores[review_sym][:scores][:min]&amp;gt;scores[round_sym][:scores][:min])&lt;br /&gt;
          scores[review_sym][:scores][:min]= scores[round_sym][:scores][:min]&lt;br /&gt;
        end&lt;br /&gt;
        if(scores[round_sym][:scores][:avg]!=nil)&lt;br /&gt;
          total_score += scores[round_sym][:scores][:avg]*length_of_assessments&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      if scores[review_sym][:scores][:max] == -999999999 &amp;amp;&amp;amp; scores[review_sym][:scores][:min] == 999999999&lt;br /&gt;
        scores[review_sym][:scores][:max] = 0&lt;br /&gt;
        scores[review_sym][:scores][:min] = 0&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      scores[review_sym][:scores][:avg] = total_score/scores[review_sym][:assessments].length.to_f&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* calculate_scores(scores) method&lt;br /&gt;
&lt;br /&gt;
  def calculate_scores(scores)&lt;br /&gt;
    # move lots of calculation from view(_participant.html.erb) to model&lt;br /&gt;
    if self.grade&lt;br /&gt;
      scores[:total_score] = self.grade&lt;br /&gt;
    else&lt;br /&gt;
      total_score = scores[:total_score]&lt;br /&gt;
      if total_score &amp;gt; 100&lt;br /&gt;
        total_score = 100&lt;br /&gt;
      end&lt;br /&gt;
      scores[:total_score] = total_score&lt;br /&gt;
      scores&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===set_handle method===&lt;br /&gt;
The set_handle method had an unncessary ELSIF statement which was performing the same action '''self.handle = self.user.name'''. This has been clubbed as an OR condition to the IF statement and the first ELSIF statement has been removed.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot;&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      elsif AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def set_handle&lt;br /&gt;
      if self.user.handle == nil or self.user.handle == &amp;quot;&amp;quot; or AssignmentParticipant.where(parent_id: self.assignment.id, handle: self.user.handle).length &amp;gt; 0&lt;br /&gt;
        self.handle = self.user.name&lt;br /&gt;
      else&lt;br /&gt;
        self.handle = self.user.handle&lt;br /&gt;
      end&lt;br /&gt;
      self.save!&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===File and directory methods===&lt;br /&gt;
The files and directory methods from AssignmentParticipant model have been moved to the '''FileHelper''' module.&lt;br /&gt;
The methods '''files''', '''submitted_files''' and '''dir_path''' are appropriate for the '''FileHelper' module and hence been moved there.&lt;br /&gt;
The below line was added to the AssignmentParticipant model.&lt;br /&gt;
include FileHelper&lt;br /&gt;
&lt;br /&gt;
The AssignmentParticipant class would look like&lt;br /&gt;
  class AssignmentParticipant &amp;lt; Participant&lt;br /&gt;
    require 'wiki_helper'&lt;br /&gt;
    '''include FileHelper'''&lt;br /&gt;
Methods moved to FileHelper:&lt;br /&gt;
&lt;br /&gt;
* submitted_files&lt;br /&gt;
&lt;br /&gt;
  def submitted_files&lt;br /&gt;
    files(self.path) if self.directory_num&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* files(directory)&lt;br /&gt;
&lt;br /&gt;
  def files(directory)&lt;br /&gt;
    files_list = Dir[directory + &amp;quot;/*&amp;quot;]&lt;br /&gt;
    files = Array.new&lt;br /&gt;
&lt;br /&gt;
    files_list.each do |file|&lt;br /&gt;
      if File.directory?(file)&lt;br /&gt;
        dir_files = files(file)&lt;br /&gt;
        dir_files.each{|f| files &amp;lt;&amp;lt; f}&lt;br /&gt;
      end&lt;br /&gt;
      files &amp;lt;&amp;lt; file&lt;br /&gt;
    end&lt;br /&gt;
    files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* submitted_files()&lt;br /&gt;
&lt;br /&gt;
  def submitted_files()&lt;br /&gt;
    files = Array.new&lt;br /&gt;
    if(self.directory_num)&lt;br /&gt;
      files = files(self.path)&lt;br /&gt;
    end&lt;br /&gt;
    return files&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
* dir_path&lt;br /&gt;
&lt;br /&gt;
  def dir_path&lt;br /&gt;
    assignment.try :directory_path&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Remove unused methods===&lt;br /&gt;
The following methods have been removed as they were not being used by the application.&lt;br /&gt;
&lt;br /&gt;
'''def average_score_per_assignment(assignment_id)'''&lt;br /&gt;
&lt;br /&gt;
 def average_score_per_assignment(assignment_id)&lt;br /&gt;
    return 0 if self.response_maps.size == 0&lt;br /&gt;
&lt;br /&gt;
    sum_of_scores = 0&lt;br /&gt;
&lt;br /&gt;
    self.response_maps.metareview_response_maps.each do |metaresponse_map|&lt;br /&gt;
      if !metaresponse_map.response.empty? &amp;amp;&amp;amp; response_map == assignment_id then&lt;br /&gt;
        sum_of_scores = sum_of_scores + response_map.response.last.average_score&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    (sum_of_scores / self.response_maps.size).to_i&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def quiz_taken_by?(contributor, reviewer)'''&lt;br /&gt;
&lt;br /&gt;
  def quiz_taken_by?(contributor, reviewer)&lt;br /&gt;
    quiz_id = QuizQuestionnaire.find_by_instructor_id(contributor.id)&lt;br /&gt;
    return QuizResponseMap.where(['reviewee_id = ? AND reviewer_id = ? AND reviewed_object_id = ?',&lt;br /&gt;
                                  self.id, reviewer.id, quiz_id]).count &amp;gt; 0&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def has_quiz?'''&lt;br /&gt;
&lt;br /&gt;
  def has_quiz?&lt;br /&gt;
    return !QuizQuestionnaire.find_by_instructor_id(self.id).nil?&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def reviewees'''&lt;br /&gt;
&lt;br /&gt;
  def reviewees&lt;br /&gt;
    reviewees = []&lt;br /&gt;
    rmaps = ResponseMap.all(conditions: [&amp;quot;reviewer_id = #{self.id} &amp;amp;&amp;amp; type = 'ReviewResponseMap'&amp;quot;])&lt;br /&gt;
        rmaps.each { |rm| reviewees.concat(AssignmentTeam.find(rm.reviewee_id).participants) }&lt;br /&gt;
&lt;br /&gt;
    reviewees&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def two_node_cycles'''&lt;br /&gt;
 &lt;br /&gt;
  def two_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap|&lt;br /&gt;
      if ap.reviewers.include?(self)&lt;br /&gt;
        self.reviews_by_reviewer(ap).nil? ? next : s01 = self.reviews_by_reviewer(ap).get_total_score&lt;br /&gt;
        ap.reviews_by_reviewer(self).nil? ? next : s10 = ap.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
        cycles.push([[self, s01], [ap, s10]])&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def three_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def three_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        if ap2.reviewers.include?(self)&lt;br /&gt;
          self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
          ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
          ap2.reviews_by_reviewer(self).nil? ? next : s20 = ap2.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
          cycles.push([[self, s01], [ap1, s12], [ap2, s20]])&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def four_node_cycles'''&lt;br /&gt;
&lt;br /&gt;
  def four_node_cycles&lt;br /&gt;
    cycles = []&lt;br /&gt;
    self.reviewers.each do |ap1|&lt;br /&gt;
      ap1.reviewers.each do |ap2|&lt;br /&gt;
        ap2.reviewers.each do |ap3|&lt;br /&gt;
          if ap3.reviewers.include?(self)&lt;br /&gt;
            self.reviews_by_reviewer(ap1).nil? ? next : s01 = self.reviews_by_reviewer(ap1).get_total_score&lt;br /&gt;
            ap1.reviews_by_reviewer(ap2).nil? ? next : s12 = ap1.reviews_by_reviewer(ap2).get_total_score&lt;br /&gt;
            ap2.reviews_by_reviewer(ap3).nil? ? next : s23 = ap2.reviews_by_reviewer(ap3).get_total_score&lt;br /&gt;
            ap3.reviews_by_reviewer(self).nil? ? next : s30 = ap3.reviews_by_reviewer(self).get_total_score&lt;br /&gt;
            cycles.push([[self, s01], [ap1, s12], [ap2, s23], [ap3, s30]])&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    cycles&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_similarity_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_similarity_score(cycle)&lt;br /&gt;
    similarity_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size-1.each do |pivot|&lt;br /&gt;
      pivot_score = cycle[pivot][1]&lt;br /&gt;
      similarity_score = similarity_score + (pivot_score - cycle[other][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    similarity_score = similarity_score / count unless count == 0.0&lt;br /&gt;
    similarity_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def cycle_deviation_score(cycle)'''&lt;br /&gt;
&lt;br /&gt;
  def cycle_deviation_score(cycle)&lt;br /&gt;
    deviation_score = 0.0&lt;br /&gt;
    count = 0.0&lt;br /&gt;
&lt;br /&gt;
    0 ... cycle.size.each do |member|&lt;br /&gt;
      participant = AssignmentParticipant.find(cycle[member][0].id)&lt;br /&gt;
      total_score = participant.get_review_score&lt;br /&gt;
      deviation_score = deviation_score + (total_score - cycle[member][1]).abs&lt;br /&gt;
      count = count + 1.0&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    deviation_score = deviation_score / count unless count == 0.0&lt;br /&gt;
    deviation_score&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def compute_quiz_scores(scores)'''&lt;br /&gt;
&lt;br /&gt;
  def compute_quiz_scores(scores)&lt;br /&gt;
    total = 0&lt;br /&gt;
    if scores[:quiz][:scores][:avg]&lt;br /&gt;
      return scores[:quiz][:scores][:avg] * 100  / 100.to_f&lt;br /&gt;
    else&lt;br /&gt;
      return 0&lt;br /&gt;
    end&lt;br /&gt;
    return total&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def review_response_maps'''&lt;br /&gt;
&lt;br /&gt;
  def review_response_maps&lt;br /&gt;
      participant = Participant.find(id)&lt;br /&gt;
      team_id = TeamsUser.team_id(participant.parent_id, participant.user_id)&lt;br /&gt;
      ReviewResponseMap.where(reviewee_id: team_id, reviewed_object_id: assignment.id)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def members'''&lt;br /&gt;
&lt;br /&gt;
  def members&lt;br /&gt;
    team.try :participants&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''def get_hash(time_stamp)'''&lt;br /&gt;
&lt;br /&gt;
  def get_hash(time_stamp)&lt;br /&gt;
    # first generate a hash from the assignment name itself&lt;br /&gt;
    hash_data = Digest::SHA1.digest(self.assignment.name.to_s)&lt;br /&gt;
&lt;br /&gt;
    # second generate a hash from the first hash plus the user name and time stamp&lt;br /&gt;
    sign = hash_data + self.user.name.to_s + time_stamp.strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)&lt;br /&gt;
    Digest::SHA1.digest(sign)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
===Review methods===&lt;br /&gt;
* The bookmark_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''BookmarkRatingQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def bookmark_reviews&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    BookmarkRatingResponseMap.get_assessments_for(participant) # participant.bookmark_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* The teammate_reviews() method from AssignmentParticipant was being called once in '''get_assessments_for''' method of '''TeammateReviewQuestionnaire''' class. It has been replaced by the method statement directly since it only had a single line of code.&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Before!!After&lt;br /&gt;
|-&lt;br /&gt;
|def teammate_reviews&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(self)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
||def get_assessments_for(participant)&lt;br /&gt;
    TeammateReviewResponseMap.get_assessments_for(participant)   #participant.teammate_reviews()&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
* Expertiza Github repository&amp;lt;ref&amp;gt;Expertiza Github repository https://github.com/expertiza/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
* Our Github repository&amp;lt;ref&amp;gt;Our Github Repository https://github.com/terryliu1995/expertiza&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cshao</name></author>
	</entry>
</feed>