codeGenius is a code annotation website dedicated to crowd-sourced annotations of code snippets, ranging from algorithm implementations to entire app source codes. The goal of codeGenius is to act as a resource for beginner programmers that allows for a deeper understanding of code. It is modeled after Rap Genius.
codeGenius is a full-stack web application developed by Timothy Hwang. The backend was created using Ruby on Rails and PostgreSQL, while the frontend uses React.JS and Flux. Styling was done entirely by myself using CSS3 / SCSS.
codeGenius uses a hand-rolled authentication system. On the back end, passwords are hashed using BCrypt. User session tokens are sent to the front-end in order to allow for single-page authentication.
Code snippets are retrieved based on popularity (view count) and recency. View count is incremented by the controller:
# snippets_controller.rb
def add_view
Snippet.increment_counter(:views, params[:id])
end
# routes.rb
get 'snippets/:id/add_view', as: 'snippet_add_view', to: 'snippets#add_view'`
Search is implemented by checking if the search query is included within each snippet title.
// resultTable.jsx
this.props.snippets.forEach(function(snippet, i) {
if (snippet.title.toLowerCase().indexOf(this.props.filterText.toLowerCase()) >= 0) {
rows.push(
// search result row component
);
}
}.bind(this));
The searchbar submits an AJAX request for all the snippet titles upon loading. Because the searchbar is shared between components, no unnecessary loading occurrs.
Users can view individual code snippets. Clicking on an annotated line reveals the annotation, while clicking on other lines opens a form to create a new annotation. Syntax highlighting is implemented using highlight.js.
The annotation logic works as follows:
- Annotations are stored with a line index.
- When displaying a snippet, the snippet body is split by the newline character (
\n
). Then, the line index is used to match annotations with snippets.
Users can also create their own snippets and annotations. Layouts for edit forms are identical to those of show pages across the site to provide a seamless user experience. Cached data is also used in order to "optimistically" load pages, further increasing responsiveness.
Snippets can be downloaded from their pages. This is done by converting the snippet's title to one safe for filenames using regex, and using send_data
to transmit the file.
# snippet.rb
def create_filename
file_ext = {
# hash containing appropriate file extensions
}
safe_title = title.gsub(/\s/, "_").gsub(/\..*/, "").gsub(/\W/, "")
"#{safe_title}.#{file_ext[language_id]}"
end
# snippets_controller.rb
def download
snippet = Snippet.find(params[:id])
send_data snippet.body, filename: snippet.create_filename
end
# routes.rb
get 'snippets/:id/download', as: 'snippet_download', to: 'snippets#download'
Each user has a profile page, where authored snippets and annotations can be accessed. JSON views are nested to optimize database queries.
- CSS for snippet title field needs to be elongated.
- Search bar only shows top ~20 results.
- Add pagination to search results, or implement a dedicated search results page.
- Allow for searching by author.
- Make decision on how to handle snippet edits -- strict (Rapgenius style -- don't allow editing at all) or loose (delete all annotations upon snippet editing).
- Pagination for user tab.