rostra 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +30 -0
  3. data/Rakefile +27 -0
  4. data/app/assets/images/rostra/vote_arrows.png +0 -0
  5. data/app/assets/javascripts/rostra/application.js +28 -0
  6. data/app/assets/javascripts/rostra/jquery.jeditable.js +543 -0
  7. data/app/assets/stylesheets/rostra/application.css +177 -0
  8. data/app/assets/stylesheets/rostra/buttons.css +43 -0
  9. data/app/assets/stylesheets/rostra/flash_messages.css +13 -0
  10. data/app/assets/stylesheets/rostra/forms.css +40 -0
  11. data/app/assets/stylesheets/rostra/questions.css +4 -0
  12. data/app/assets/stylesheets/rostra/reset.css +13 -0
  13. data/app/assets/stylesheets/rostra/typography.css +7 -0
  14. data/app/controllers/rostra/answers_controller.rb +47 -0
  15. data/app/controllers/rostra/application_controller.rb +31 -0
  16. data/app/controllers/rostra/questions_controller.rb +57 -0
  17. data/app/helpers/rostra/application_helper.rb +4 -0
  18. data/app/helpers/rostra/questions_helper.rb +4 -0
  19. data/app/models/rostra/ability.rb +27 -0
  20. data/app/models/rostra/answer.rb +10 -0
  21. data/app/models/rostra/question.rb +15 -0
  22. data/app/models/rostra/vote.rb +19 -0
  23. data/app/models/vote.rb +17 -0
  24. data/app/views/layouts/rostra/application.html.erb +23 -0
  25. data/app/views/rostra/answers/_form.html.erb +8 -0
  26. data/app/views/rostra/answers/edit.html.erb +7 -0
  27. data/app/views/rostra/answers/vote.js.erb +1 -0
  28. data/app/views/rostra/questions/_form.html.erb +7 -0
  29. data/app/views/rostra/questions/edit.html.erb +7 -0
  30. data/app/views/rostra/questions/index.html.erb +45 -0
  31. data/app/views/rostra/questions/new.html.erb +7 -0
  32. data/app/views/rostra/questions/show.html.erb +47 -0
  33. data/app/views/rostra/questions/vote.js.erb +1 -0
  34. data/app/views/rostra/shared/_answers_votes.html.erb +27 -0
  35. data/app/views/rostra/shared/_sidebar.html.erb +8 -0
  36. data/app/views/rostra/shared/_votes.html.erb +27 -0
  37. data/config/cucumber.yml +8 -0
  38. data/config/initializers/client_side_validations.rb +14 -0
  39. data/config/initializers/simple_form.rb +93 -0
  40. data/config/locales/simple_form.en.yml +24 -0
  41. data/config/routes.rb +10 -0
  42. data/db/migrate/20110918170142_create_rostra_questions.rb +10 -0
  43. data/db/migrate/20111003233228_acts_as_taggable_on_migration.rb +28 -0
  44. data/db/migrate/20111005012613_add_user_id_to_questions.rb +5 -0
  45. data/db/migrate/20111007205730_create_rostra_answers.rb +11 -0
  46. data/db/migrate/20111008224511_thumbs_up_migration.rb +25 -0
  47. data/lib/rostra/engine.rb +13 -0
  48. data/lib/rostra/version.rb +3 -0
  49. data/lib/rostra.rb +11 -0
  50. data/lib/tasks/cucumber.rake +65 -0
  51. data/lib/tasks/rake_routes.rake +40 -0
  52. data/lib/tasks/rostra_tasks.rake +4 -0
  53. data/lib/templates/erb/scaffold/_form.html.erb +13 -0
  54. metadata +273 -0
@@ -0,0 +1,47 @@
1
+ <h1><%= @question.title %></h1>
2
+
3
+ <%= render 'rostra/shared/sidebar' %>
4
+
5
+ <div id="page_content">
6
+
7
+ <div class="question">
8
+ <%= render 'rostra/shared/votes' %>
9
+ <h3 class="title"><%= @question.title %></h3>
10
+
11
+ <cite>
12
+ Asked by <%= @question.user.name %>
13
+ <%= link_to 'edit', edit_question_path(@question) if can? :manage, @question %>
14
+ </cite>
15
+ <div class="text"><%= simple_format(@question.details) %></div>
16
+ <div class="timestamp"><%= time_ago_in_words(@question.updated_at) %> ago</div>
17
+ <div class="tags">
18
+ Tags:
19
+ <% @question.tags.each do |tag| %>
20
+ <%= link_to tag, "" %>
21
+ <% end %>
22
+ </div>
23
+ </div>
24
+
25
+ <% unless @answers.empty? %>
26
+ <h3 id="answer_count"><%= pluralize(@answers.size, 'Answer') %></h3>
27
+ <div id="answers">
28
+ <% @answers.each do |answer| %>
29
+ <div class="answer" id="<%= dom_id(answer) %>">
30
+ <%= render partial: 'rostra/shared/answers_votes', locals: {answer: answer} %>
31
+ <cite>
32
+ <%= answer.user.name %> says:
33
+ <%= link_to('edit', edit_question_answer_path(@question, answer)) if can? :manage, answer %>
34
+ </cite>
35
+ <div class="text"><%= simple_format(answer.text) %></div>
36
+ <div class="timestamp"><%= time_ago_in_words(answer.updated_at) %> ago</div>
37
+ </div>
38
+ <% end %>
39
+ </div>
40
+ <% end %>
41
+
42
+ <% if user_signed_in? %>
43
+ <%= render 'rostra/answers/form' %>
44
+ <% else %>
45
+ <%= link_to "Login to answer this question", main_app.new_user_session_path, class: 'button' %>
46
+ <% end %>
47
+ </div><!-- page_content -->
@@ -0,0 +1 @@
1
+ $('.vote_wrapper').replaceWith('<%= escape_javascript(render 'rostra/shared/votes') %>');
@@ -0,0 +1,27 @@
1
+ <div class="answers_vote_wrapper">
2
+
3
+ <% if user_signed_in? %>
4
+
5
+ <% up_selected = current_user.voted_for?(answer) ? 'selected' : "" %>
6
+ <%= link_to('Vote Answer Up', vote_question_answer_path(@question, answer, vote_type: 'up'), method: :put, remote: true, class: "vote up #{up_selected}") %>
7
+
8
+ <div class="count"><%= answer.plusminus %></div>
9
+
10
+ <% down_selected = current_user.voted_against?(answer) ? 'selected' : "" %>
11
+ <%= link_to('Vote Answer Down', vote_question_answer_path(@question, answer, vote_type: 'down'), method: :put, remote: true, class: "vote down #{down_selected}") %>
12
+
13
+ <% else %>
14
+
15
+ <%= link_to('Vote Answer Up', '#', class: "answers vote up login_flash") %>
16
+ <div class="count"><%= answer.plusminus %></div>
17
+ <%= link_to('Vote Answer Down', '#', class: "vote down login_flash") %>
18
+
19
+ <% end %>
20
+
21
+ </div>
22
+
23
+ <% unless user_signed_in? %>
24
+ <div class="hidden flash" id="flash_notice">
25
+ You must <%= link_to 'login', main_app.new_user_session_path %> or <%= link_to 'signup', main_app.new_user_registration_path %> in order to vote
26
+ </div>
27
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <div id="sidebar">
2
+ <% if user_signed_in? %>
3
+ <%= link_to 'Ask a question', new_question_path, class: "button" %>
4
+ <% else %>
5
+ <%= link_to 'Login to ask a question', main_app.new_user_session_path, class: "button" %>
6
+ <% end %>
7
+ </div><!--sidebar-->
8
+
@@ -0,0 +1,27 @@
1
+ <div class="vote_wrapper">
2
+
3
+ <% if user_signed_in? %>
4
+
5
+ <% up_selected = current_user.voted_for?(@question) ? 'selected' : "" %>
6
+ <%= link_to('Vote Question Up', vote_question_path(@question, vote_type: 'up'), method: :put, remote: true, class: "vote up #{up_selected}") %>
7
+
8
+ <div class="count"><%= @question.plusminus %></div>
9
+
10
+ <% down_selected = current_user.voted_against?(@question) ? 'selected' : "" %>
11
+ <%= link_to('Vote Question Down', vote_question_path(@question, vote_type: 'down'), method: :put, remote: true, class: "vote down #{down_selected}") %>
12
+
13
+ <% else %>
14
+
15
+ <%= link_to('Vote Question Up', '#', class: "vote up login_flash") %>
16
+ <div class="count"><%= @question.plusminus %></div>
17
+ <%= link_to('Vote Question Down', '#', class: "vote down login_flash") %>
18
+
19
+ <% end %>
20
+
21
+ </div>
22
+
23
+ <% unless user_signed_in? %>
24
+ <div class="hidden flash" id="flash_notice">
25
+ You must <%= link_to 'login', main_app.new_user_session_path %> or <%= link_to 'signup', main_app.new_user_registration_path %> in order to vote
26
+ </div>
27
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
5
+ %>
6
+ default: <%= std_opts %> features
7
+ wip: --tags @wip:3 --wip features
8
+ rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
@@ -0,0 +1,14 @@
1
+ # ClientSideValidations Initializer
2
+
3
+ require 'client_side_validations/simple_form' if defined?(::SimpleForm)
4
+ require 'client_side_validations/formtastic' if defined?(::Formtastic)
5
+
6
+ # Uncomment the following block if you want each input field to have the validation messages attached.
7
+ # ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
8
+ # unless html_tag =~ /^<label/
9
+ # %{<div class="field_with_errors">#{html_tag}<label for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</label></div>}.html_safe
10
+ # else
11
+ # %{<div class="field_with_errors">#{html_tag}</div>}.html_safe
12
+ # end
13
+ # end
14
+
@@ -0,0 +1,93 @@
1
+ # Use this setup block to configure all options available in SimpleForm.
2
+ SimpleForm.setup do |config|
3
+ # Components used by the form builder to generate a complete input. You can remove
4
+ # any of them, change the order, or even add your own components to the stack.
5
+ # config.components = [ :placeholder, :label_input, :hint, :error ]
6
+
7
+ # Default tag used on hints.
8
+ # config.hint_tag = :span
9
+
10
+ # CSS class to add to all hint tags.
11
+ # config.hint_class = :hint
12
+
13
+ # CSS class used on errors.
14
+ # config.error_class = :error
15
+
16
+ # Default tag used on errors.
17
+ # config.error_tag = :span
18
+
19
+ # Method used to tidy up errors.
20
+ # config.error_method = :first
21
+
22
+ # Default tag used for error notification helper.
23
+ # config.error_notification_tag = :p
24
+
25
+ # CSS class to add for error notification helper.
26
+ # config.error_notification_class = :error_notification
27
+
28
+ # ID to add for error notification helper.
29
+ # config.error_notification_id = nil
30
+
31
+ # You can wrap all inputs in a pre-defined tag.
32
+ # config.wrapper_tag = :div
33
+
34
+ # CSS class to add to all wrapper tags.
35
+ config.wrapper_class = :field
36
+
37
+ # CSS class to add to the wrapper if the field has errors.
38
+ # config.wrapper_error_class = :field_with_errors
39
+
40
+ # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
41
+ # config.collection_wrapper_tag = nil
42
+
43
+ # You can wrap each item in a collection of radio/check boxes with a tag, defaulting to span.
44
+ # config.item_wrapper_tag = :span
45
+
46
+ # Series of attempts to detect a default label method for collection.
47
+ # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
48
+
49
+ # Series of attempts to detect a default value method for collection.
50
+ # config.collection_value_methods = [ :id, :to_s ]
51
+
52
+ # How the label text should be generated altogether with the required text.
53
+ config.label_text = lambda { |label, required| "#{label} #{required}" }
54
+
55
+ # You can define the class to use on all labels. Default is nil.
56
+ # config.label_class = nil
57
+
58
+ # You can define the class to use on all forms. Default is simple_form.
59
+ # config.form_class = :simple_form
60
+
61
+ # Whether attributes are required by default (or not). Default is true.
62
+ # config.required_by_default = true
63
+
64
+ # Tell browsers whether to use default HTML5 validations (novalidate option).
65
+ # Default is enabled.
66
+ config.browser_validations = false
67
+
68
+ # Determines whether HTML5 types (:email, :url, :search, :tel) and attributes
69
+ # (e.g. required) are used or not. True by default.
70
+ # Having this on in non-HTML5 compliant sites can cause odd behavior in
71
+ # HTML5-aware browsers such as Chrome.
72
+ # config.html5 = true
73
+
74
+ # Custom mappings for input types. This should be a hash containing a regexp
75
+ # to match as key, and the input type that will be used when the field name
76
+ # matches the regexp as value.
77
+ # config.input_mappings = { /count/ => :integer }
78
+
79
+ # Collection of methods to detect if a file type was given.
80
+ # config.file_methods = [ :mounted_as, :file?, :public_filename ]
81
+
82
+ # Default priority for time_zone inputs.
83
+ # config.time_zone_priority = nil
84
+
85
+ # Default priority for country inputs.
86
+ # config.country_priority = nil
87
+
88
+ # Default size for text inputs.
89
+ # config.default_input_size = 50
90
+
91
+ # When false, do not use translations for labels, hints or placeholders.
92
+ # config.translate = true
93
+ end
@@ -0,0 +1,24 @@
1
+ en:
2
+ simple_form:
3
+ "yes": 'Yes'
4
+ "no": 'No'
5
+ required:
6
+ text: 'required'
7
+ mark: '*'
8
+ # You can uncomment the line below if you need to overwrite the whole required html.
9
+ # When using html, text and mark won't be used.
10
+ # html: '<abbr title="required">*</abbr>'
11
+ error_notification:
12
+ default_message: "Some errors were found, please take a look:"
13
+ # Labels and hints examples
14
+ # labels:
15
+ # password: 'Password'
16
+ # user:
17
+ # new:
18
+ # email: 'E-mail para efetuar o sign in.'
19
+ # edit:
20
+ # email: 'E-mail.'
21
+ # hints:
22
+ # username: 'User name to sign in.'
23
+ # password: 'No special characters, please.'
24
+
data/config/routes.rb ADDED
@@ -0,0 +1,10 @@
1
+ Rostra::Engine.routes.draw do
2
+ resources :questions do
3
+ put :vote, :on => :member
4
+ resources :answers do
5
+ put :vote, :on => :member
6
+ end
7
+ end
8
+
9
+ root :to => "questions#index"
10
+ end
@@ -0,0 +1,10 @@
1
+ class CreateRostraQuestions < ActiveRecord::Migration
2
+ def change
3
+ create_table :rostra_questions do |t|
4
+ t.string :title
5
+ t.text :details
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,28 @@
1
+ class ActsAsTaggableOnMigration < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :tags do |t|
4
+ t.string :name
5
+ end
6
+
7
+ create_table :taggings do |t|
8
+ t.references :tag
9
+
10
+ # You should make sure that the column created is
11
+ # long enough to store the required class names.
12
+ t.references :taggable, :polymorphic => true
13
+ t.references :tagger, :polymorphic => true
14
+
15
+ t.string :context
16
+
17
+ t.datetime :created_at
18
+ end
19
+
20
+ add_index :taggings, :tag_id
21
+ add_index :taggings, [:taggable_id, :taggable_type, :context]
22
+ end
23
+
24
+ def self.down
25
+ drop_table :taggings
26
+ drop_table :tags
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ class AddUserIdToQuestions < ActiveRecord::Migration
2
+ def change
3
+ add_column :rostra_questions, :user_id, :integer
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ class CreateRostraAnswers < ActiveRecord::Migration
2
+ def change
3
+ create_table :rostra_answers do |t|
4
+ t.integer :user_id
5
+ t.integer :question_id
6
+ t.text :text
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ class ThumbsUpMigration < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :votes, :force => true do |t|
4
+
5
+ t.boolean :vote, :default => false
6
+ t.references :voteable, :polymorphic => true, :null => false
7
+ t.references :voter, :polymorphic => true
8
+ t.timestamps
9
+
10
+ end
11
+
12
+ add_index :votes, [:voter_id, :voter_type]
13
+ add_index :votes, [:voteable_id, :voteable_type]
14
+
15
+
16
+ # Comment out the line below to allow multiple votes per voter on a single entity.
17
+ add_index :votes, [:voter_id, :voter_type, :voteable_id, :voteable_type], :unique => true, :name => 'fk_one_vote_per_user_per_entity'
18
+
19
+ end
20
+
21
+ def self.down
22
+ drop_table :votes
23
+ end
24
+
25
+ end
@@ -0,0 +1,13 @@
1
+ module Rostra
2
+ class Engine < Rails::Engine
3
+ require 'acts-as-taggable-on'
4
+ require 'cancan'
5
+ require 'simple_form'
6
+ require 'jquery-rails'
7
+ require 'client_side_validations'
8
+ require 'thumbs_up'
9
+ require 'grb'
10
+
11
+ isolate_namespace Rostra
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Rostra
2
+ VERSION = "0.0.1"
3
+ end
data/lib/rostra.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "rostra/engine"
2
+
3
+ module Rostra
4
+
5
+ # def self.included(base)
6
+ # def base.rostra
7
+ # base.has_many :questions
8
+ # end
9
+ # end
10
+
11
+ end
@@ -0,0 +1,65 @@
1
+ # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
2
+ # It is recommended to regenerate this file in the future when you upgrade to a
3
+ # newer version of cucumber-rails. Consider adding your own code to a new file
4
+ # instead of editing this one. Cucumber will automatically load all features/**/*.rb
5
+ # files.
6
+
7
+
8
+ unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
9
+
10
+ vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
11
+ $LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
12
+
13
+ begin
14
+ require 'cucumber/rake/task'
15
+
16
+ namespace :cucumber do
17
+ Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t|
18
+ t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
19
+ t.fork = true # You may get faster startup if you set this to false
20
+ t.profile = 'default'
21
+ end
22
+
23
+ Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t|
24
+ t.binary = vendored_cucumber_bin
25
+ t.fork = true # You may get faster startup if you set this to false
26
+ t.profile = 'wip'
27
+ end
28
+
29
+ Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t|
30
+ t.binary = vendored_cucumber_bin
31
+ t.fork = true # You may get faster startup if you set this to false
32
+ t.profile = 'rerun'
33
+ end
34
+
35
+ desc 'Run all features'
36
+ task :all => [:ok, :wip]
37
+
38
+ task :statsetup do
39
+ require 'rails/code_statistics'
40
+ ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features')
41
+ ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features')
42
+ end
43
+ end
44
+ desc 'Alias for cucumber:ok'
45
+ task :cucumber => 'cucumber:ok'
46
+
47
+ task :default => :cucumber
48
+
49
+ task :features => :cucumber do
50
+ STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
51
+ end
52
+
53
+ # In case we don't have ActiveRecord, append a no-op task that we can depend upon.
54
+ task 'db:test:prepare' do
55
+ end
56
+
57
+ task :stats => 'cucumber:statsetup'
58
+ rescue LoadError
59
+ desc 'cucumber rake task not available (cucumber not installed)'
60
+ task :cucumber do
61
+ abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
62
+ end
63
+ end
64
+
65
+ end
@@ -0,0 +1,40 @@
1
+ # Essentially copy rake routes task from core rails in order to have this during development
2
+ # See: http://stackoverflow.com/questions/7431687/listing-rake-routes-for-a-mountable-rails-3-1-engine
3
+ #
4
+ desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
5
+ task :routes => :environment do
6
+ Rails.application.reload_routes!
7
+ all_routes = Rostra::Engine.routes.routes
8
+
9
+ if ENV['CONTROLLER']
10
+ all_routes = all_routes.select{ |route| route.defaults[:controller] == ENV['CONTROLLER'] }
11
+ end
12
+
13
+ routes = all_routes.collect do |route|
14
+
15
+ reqs = route.requirements.dup
16
+ rack_app = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/
17
+
18
+ endpoint = rack_app ? rack_app.inspect : "#{reqs[:controller]}##{reqs[:action]}"
19
+ constraints = reqs.except(:controller, :action)
20
+
21
+ reqs = endpoint == '#' ? '' : endpoint
22
+
23
+ unless constraints.empty?
24
+ reqs = reqs.empty? ? constraints.inspect : "#{reqs} #{constraints.inspect}"
25
+ end
26
+
27
+ {:name => route.name.to_s, :verb => route.verb.to_s, :path => route.path, :reqs => reqs}
28
+ end
29
+
30
+ # Skip the route if it's internal info route
31
+ routes.reject! { |r| r[:path] =~ %r{/rails/info/properties|^/assets} }
32
+
33
+ name_width = routes.map{ |r| r[:name].length }.max
34
+ verb_width = routes.map{ |r| r[:verb].length }.max
35
+ path_width = routes.map{ |r| r[:path].length }.max
36
+
37
+ routes.each do |r|
38
+ puts "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
39
+ end
40
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :rostra do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,13 @@
1
+ <%%= simple_form_for(@<%= singular_table_name %>) do |f| %>
2
+ <%%= f.error_notification %>
3
+
4
+ <div class="inputs">
5
+ <%- attributes.each do |attribute| -%>
6
+ <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %>
7
+ <%- end -%>
8
+ </div>
9
+
10
+ <div class="actions">
11
+ <%%= f.button :submit %>
12
+ </div>
13
+ <%% end %>