irwi 0.0.0

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 (49) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +53 -0
  5. data/Rakefile +53 -0
  6. data/VERSION +1 -0
  7. data/app/views/base_wiki_pages/_wiki_page_actions.html.erb +4 -0
  8. data/app/views/base_wiki_pages/_wiki_page_history.html.erb +31 -0
  9. data/app/views/base_wiki_pages/_wiki_page_info.html.erb +3 -0
  10. data/app/views/base_wiki_pages/_wiki_page_style.html.erb +69 -0
  11. data/app/views/base_wiki_pages/compare.html.erb +13 -0
  12. data/app/views/base_wiki_pages/edit.html.erb +14 -0
  13. data/app/views/base_wiki_pages/history.html.erb +7 -0
  14. data/app/views/base_wiki_pages/no.html.erb +1 -0
  15. data/app/views/base_wiki_pages/not_allowed.html.erb +1 -0
  16. data/app/views/base_wiki_pages/show.html.erb +10 -0
  17. data/generators/irwi_wiki/irwi_wiki_generator.rb +22 -0
  18. data/generators/irwi_wiki/templates/controllers/wiki_pages_controller.rb +5 -0
  19. data/generators/irwi_wiki/templates/helpers/wiki_pages_helper.rb +3 -0
  20. data/generators/irwi_wiki/templates/migrate/create_wiki_pages.rb +44 -0
  21. data/generators/irwi_wiki/templates/models/wiki_page.rb +5 -0
  22. data/generators/irwi_wiki/templates/models/wiki_page_version.rb +5 -0
  23. data/irwi.gemspec +99 -0
  24. data/lib/irwi.rb +7 -0
  25. data/lib/irwi/comparators/base.rb +17 -0
  26. data/lib/irwi/comparators/diff_lcs.rb +52 -0
  27. data/lib/irwi/comparators/spans/changed_span.rb +18 -0
  28. data/lib/irwi/comparators/spans/not_changed_span.rb +20 -0
  29. data/lib/irwi/config.rb +18 -0
  30. data/lib/irwi/extensions/controllers/wiki_pages.rb +123 -0
  31. data/lib/irwi/extensions/models/wiki_page.rb +46 -0
  32. data/lib/irwi/extensions/models/wiki_page_version.rb +40 -0
  33. data/lib/irwi/formatters/blue_cloth.rb +11 -0
  34. data/lib/irwi/formatters/red_cloth.rb +11 -0
  35. data/lib/irwi/helpers/wiki_pages_helper.rb +83 -0
  36. data/lib/irwi/support/route_mapper.rb +17 -0
  37. data/lib/irwi/support/template_finder.rb +11 -0
  38. data/rails/init.rb +31 -0
  39. data/spec/comparators/diff_lcs_spec.rb +37 -0
  40. data/spec/config_spec.rb +58 -0
  41. data/spec/extensions/controllers/wiki_pages_spec.rb +53 -0
  42. data/spec/helpers/wiki_pages_helper_spec.rb +74 -0
  43. data/spec/rcov.opts +2 -0
  44. data/spec/spec.opts +4 -0
  45. data/spec/spec_helper.rb +15 -0
  46. data/spec/support/route_mapper_spec.rb +20 -0
  47. data/spec/support/template_finder_spec.rb +33 -0
  48. data/tasks/riwiki_tasks.rake +4 -0
  49. metadata +127 -0
@@ -0,0 +1,7 @@
1
+ module Irwi
2
+
3
+ def self.config
4
+ @@config ||= Irwi::Config.new
5
+ end
6
+
7
+ end
@@ -0,0 +1,17 @@
1
+ class Irwi::Comparators::Base
2
+
3
+ def render_changes( old_text, new_text )
4
+ build_changes( old_text, new_text ).join('')
5
+ end
6
+
7
+ protected
8
+
9
+ def new_not_changed( value )
10
+ Irwi::Comparators::Spans::NotChangedSpan.new( value )
11
+ end
12
+
13
+ def new_changed( action, old_value, new_value )
14
+ Irwi::Comparators::Spans::ChangedSpan.new( action, old_value, new_value )
15
+ end
16
+
17
+ end
@@ -0,0 +1,52 @@
1
+ class Irwi::Comparators::DiffLcs < Irwi::Comparators::Base
2
+
3
+ def initialize
4
+ super
5
+
6
+ require 'diff/lcs'
7
+ end
8
+
9
+ def build_changes( old_text, new_text )
10
+ diffs = Diff::LCS.sdiff( old_text || '', new_text || '' ) # Building symmetric diff sequence
11
+ changes = [] # Array for our result changes
12
+
13
+ diffs.each do |change|
14
+ case change.action
15
+ when '=' then
16
+ if !changes.empty? && changes.last.action == '=' # Append to last not changed span, if exists
17
+ changes.last.value << change.old_element
18
+ else
19
+ changes << new_not_changed( change.old_element )
20
+ end
21
+
22
+ when '+' then
23
+ if !changes.empty? && changes.last.action == '+' # Append to last addition, if exists
24
+ changes.last.new_value << change.new_element
25
+ elsif !changes.empty? && changes.last.action == '!' # Append to last replace, if exists (it's necessary when replacing short string with a new long)
26
+ changes.last.new_value << change.new_element
27
+ else
28
+ changes << new_changed( '+', nil, change.new_element )
29
+ end
30
+
31
+ when '-' then
32
+ if !changes.empty? && changes.last.action == '-' # Append to last deletion, if exists
33
+ changes.last.old_value << change.old_element
34
+ else
35
+ changes << new_changed( '-', change.old_element, nil )
36
+ end
37
+
38
+ when '!' then
39
+ if !changes.empty? && changes.last.action == '!' # Append to last replace, if exists
40
+ changes.last.old_value << change.old_element
41
+ changes.last.new_value << change.new_element
42
+ else
43
+ changes << new_changed( '!', change.old_element, change.new_element )
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ changes
50
+ end
51
+
52
+ end
@@ -0,0 +1,18 @@
1
+ class Irwi::Comparators::Spans::ChangedSpan
2
+
3
+ attr_accessor :action, :old_value, :new_value
4
+
5
+ def initialize( act, ov, nv )
6
+ @action = act
7
+ @old_value = ov
8
+ @new_value = nv
9
+ end
10
+
11
+ def to_s
12
+ s = ''
13
+ s << "<span class=\"removed\">#{@old_value}</span>" if @old_value
14
+ s << "<span class=\"added\">#{@new_value}</span>" if @new_value
15
+ s
16
+ end
17
+
18
+ end
@@ -0,0 +1,20 @@
1
+ class Irwi::Comparators::Spans::NotChangedSpan
2
+
3
+ attr_accessor :value
4
+
5
+ def initialize( v )
6
+ @value = v
7
+ end
8
+
9
+ def to_s
10
+ @value
11
+ end
12
+
13
+ def action
14
+ '='
15
+ end
16
+
17
+ alias_method :old_value, :value
18
+ alias_method :new_value, :value
19
+
20
+ end
@@ -0,0 +1,18 @@
1
+ class Irwi::Config
2
+
3
+ attr_accessor_with_default :user_class_name, 'User'
4
+
5
+ attr_accessor_with_default :page_class_name, 'WikiPage'
6
+ attr_accessor_with_default :page_version_class_name, 'WikiPageVersion'
7
+
8
+ attr_accessor_with_default :page_version_foreign_key, 'page_id'
9
+
10
+ attr_accessor_with_default :formatter do
11
+ Irwi::Formatters::RedCloth.new
12
+ end
13
+
14
+ attr_accessor_with_default :comparator do
15
+ Irwi::Comparators::DiffLcs.new
16
+ end
17
+
18
+ end
@@ -0,0 +1,123 @@
1
+ module Irwi::Extensions::Controllers::WikiPages
2
+
3
+ module ClassMethods
4
+
5
+ def page_class
6
+ @page_class ||= Irwi.config.page_class_name.constantize
7
+ end
8
+
9
+ def set_page_class(arg)
10
+ @page_class = arg
11
+ end
12
+
13
+ end
14
+
15
+ module InstanceMethods
16
+
17
+ include Irwi::Support::TemplateFinder
18
+
19
+ def show
20
+ return not_allowed unless show_allowed?
21
+
22
+ render_template( @page.new_record? ? 'no' : 'show' )
23
+ end
24
+
25
+ def history
26
+ return not_allowed unless show_allowed? && history_allowed?
27
+
28
+ render_template( @page.new_record? ? 'no' : 'history' )
29
+ end
30
+
31
+ def compare
32
+ return not_allowed unless show_allowed? && history_allowed?
33
+
34
+ if @page.new_record?
35
+ render_template 'no'
36
+ else
37
+ @versions = @page.versions.between( params[:old] || 1, params[:new] || @page.last_version_number ).all # Loading all versions between first and last
38
+
39
+ @new_version = @versions.last # Loading next version
40
+ @old_version = @versions.first # Loading previous version
41
+
42
+ render_template 'compare'
43
+ end
44
+ end
45
+
46
+ def edit
47
+ return not_allowed unless show_allowed? && edit_allowed?
48
+
49
+ render_template 'edit'
50
+ end
51
+
52
+ def update
53
+ return not_allowed unless @page.new_record? || ( show_allowed? && edit_allowed? ) # Check for rights (but not for new record, for it we will use second check only)
54
+
55
+ @page.attributes = params[:page] # Assign new attributes
56
+
57
+ return not_allowed unless show_allowed? && edit_allowed? # Double check: used beacause action may become invalid after attributes update
58
+
59
+ @page.updator = @current_user # Assing user, which updated page
60
+ @page.creator = @current_user if @page.new_record? # Assign it's creator if it's new page
61
+
62
+ if @page.save
63
+ redirect_to url_for( :action => :show, :path => @page.path.split('/') ) # redirect to new page's path (if it changed)
64
+ else
65
+ render_template 'edit'
66
+ end
67
+ end
68
+
69
+ protected
70
+
71
+ # Retrieves wiki_page_class for this controller
72
+ def page_class
73
+ self.class.page_class
74
+ end
75
+
76
+ # Renders user-specified or default template
77
+ def render_template( template )
78
+ render "#{template_dir template}/#{template}"
79
+ end
80
+
81
+ # Initialize @current_user instance variable
82
+ def setup_current_user
83
+ @current_user = respond_to?( :current_user ) ? current_user : nil # Find user by current_user method or return nil
84
+ end
85
+
86
+ # Initialize @page instance variable
87
+ def setup_page
88
+ @page = page_class.find_by_path_or_new( params[:path].join('/') ) # Find existing page by path or create new
89
+ end
90
+
91
+ # Method, which called when user tries to visit
92
+ def not_allowed
93
+ render_template 'not_allowed'
94
+ end
95
+
96
+ # Check is it allowed for current user to see current page. Designed to be redefined by application programmer
97
+ def show_allowed?
98
+ true
99
+ end
100
+
101
+ # Check is it allowed for current user see current page history. Designed to be redefined by application programmer
102
+ def history_allowed?
103
+ true
104
+ end
105
+
106
+ # Check is it allowed for current user edit current page. Designed to be redefined by application programmer
107
+ def edit_allowed?
108
+ true
109
+ end
110
+
111
+ end
112
+
113
+ def self.included( base )
114
+ base.send :extend, Irwi::Extensions::Controllers::WikiPages::ClassMethods
115
+ base.send :include, Irwi::Extensions::Controllers::WikiPages::InstanceMethods
116
+
117
+ base.before_filter :setup_current_user # Setup @current_user instance variable before each action
118
+ base.before_filter :setup_page # Setup @page instance variable before each action
119
+
120
+ base.helper_method :show_allowed?, :edit_allowed?, :history_allowed? # Access control methods are avaliable in views
121
+ end
122
+
123
+ end
@@ -0,0 +1,46 @@
1
+ module Irwi::Extensions::Models::WikiPage
2
+
3
+ module ClassMethods
4
+
5
+ def find_by_path_or_new( path )
6
+ self.find_by_path( path ) || self.new( :path => path )
7
+ end
8
+
9
+ end
10
+
11
+ module InstanceMethods
12
+
13
+ # Retrieve number of last version
14
+ def last_version_number
15
+ last = versions.last
16
+ last ? last.number : 0
17
+ end
18
+
19
+ protected
20
+
21
+ def create_new_version
22
+ n = last_version_number
23
+
24
+ v = versions.build
25
+ v.attributes = attributes.slice( *v.attribute_names )
26
+ v.number = n + 1
27
+ v.save!
28
+ end
29
+
30
+ end
31
+
32
+ def self.included( base )
33
+ base.send :extend, Irwi::Extensions::Models::WikiPage::ClassMethods
34
+ base.send :include, Irwi::Extensions::Models::WikiPage::InstanceMethods
35
+
36
+ base.send :attr_accessor, :comment, :previous_version_number
37
+
38
+ base.belongs_to :creator, :class_name => Irwi.config.user_class_name
39
+ base.belongs_to :updator, :class_name => Irwi.config.user_class_name
40
+
41
+ base.has_many :versions, :class_name => Irwi.config.page_version_class_name, :foreign_key => Irwi.config.page_version_foreign_key, :order => 'id ASC'
42
+
43
+ base.after_save :create_new_version
44
+ end
45
+
46
+ end
@@ -0,0 +1,40 @@
1
+ module Irwi::Extensions::Models::WikiPageVersion
2
+
3
+ module ClassMethods
4
+
5
+ end
6
+
7
+ module InstanceMethods
8
+
9
+ def next
10
+ self.class.first :conditions => ["id > ? AND page_id = ?", id, page_id], :order => 'id ASC'
11
+ end
12
+
13
+ def previous
14
+ self.class.first :conditions => ["id < ? AND page_id = ?", id, page_id], :order => 'id DESC'
15
+ end
16
+
17
+ protected
18
+
19
+ def raise_on_update
20
+ raise ActiveRecordError.new "Cann't modify existent version"
21
+ end
22
+
23
+ end
24
+
25
+ def self.included( base )
26
+ base.send :extend, Irwi::Extensions::Models::WikiPageVersion::ClassMethods
27
+ base.send :include, Irwi::Extensions::Models::WikiPageVersion::InstanceMethods
28
+
29
+ base.belongs_to :page, :class_name => Irwi.config.page_class_name
30
+ base.belongs_to :updator, :class_name => Irwi.config.user_class_name
31
+
32
+ base.before_update :raise_on_update
33
+
34
+ base.named_scope :between, lambda { | first, last |
35
+ first, last = last, first if last < first # Reordering if neeeded
36
+ { :conditions => [ 'number >= ? AND number <= ?', first, last ] }
37
+ }
38
+ end
39
+
40
+ end
@@ -0,0 +1,11 @@
1
+ class Irwi::Formatters::BlueCloth
2
+
3
+ def initialize
4
+ require 'bluecloth'
5
+ end
6
+
7
+ def format( text )
8
+ BlueCloth.new( text ).to_html
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ class Irwi::Formatters::RedCloth
2
+
3
+ def initialize
4
+ require 'redcloth'
5
+ end
6
+
7
+ def format( text )
8
+ ::RedCloth.new( text ).to_html
9
+ end
10
+
11
+ end
@@ -0,0 +1,83 @@
1
+ module Irwi::Helpers::WikiPagesHelper
2
+
3
+ include Irwi::Support::TemplateFinder
4
+
5
+ # Edit form for wiki page model
6
+ def wiki_page_form( config = {}, &block )
7
+ form_for( :page, @page, { :url => url_for( :action => :update ), :html=> { :class => 'wiki_form' } }.merge!( config ), &block )
8
+ end
9
+
10
+ def wiki_page_edit_path
11
+ url_for( :action => :edit )
12
+ end
13
+
14
+ def wiki_page_history_path
15
+ url_for( :action => :history )
16
+ end
17
+
18
+ def wiki_page_compare_path
19
+ url_for( :action => :compare )
20
+ end
21
+
22
+ def wiki_page_path
23
+ url_for( :action => :show )
24
+ end
25
+
26
+ def wiki_content( text )
27
+ sanitize( Irwi.config.formatter.format( text ) )
28
+ end
29
+
30
+ def wiki_diff( old_text, new_text )
31
+ Irwi.config.comparator.render_changes( old_text, new_text )
32
+ end
33
+
34
+ def wiki_user( user )
35
+ return '&lt;Unknown&gt;' if user.nil?
36
+
37
+ "User##{user.id}"
38
+ end
39
+
40
+ ##
41
+ # Instead of having to translate strings and defining a default value:
42
+ #
43
+ # t("Hello World!", :default => 'Hello World!')
44
+ #
45
+ # We define this method to define the value only once:
46
+ #
47
+ # wt("Hello World!")
48
+ #
49
+ # Note that interpolation still works ...
50
+ #
51
+ # wt("Hello {{world}}!", :world => @world)
52
+ #
53
+ def wt(msg, *args)
54
+ config = args.extract_options!
55
+ config[:default] = msg
56
+ config[:scope] = 'wiki'
57
+ I18n.t(msg, config)
58
+ end
59
+
60
+ def wiki_page_style
61
+ render :partial => "#{template_dir '_wiki_page_style'}/wiki_page_style"
62
+ end
63
+
64
+ def wiki_page_info(page = nil)
65
+ page ||= @page # By default take page from instance variable
66
+
67
+ render :partial => "#{template_dir '_wiki_page_info'}/wiki_page_info", :locals => { :page => page }
68
+ end
69
+
70
+ def wiki_page_actions(page = nil)
71
+ page ||= @page # By default take page from instance variable
72
+
73
+ render :partial => "#{template_dir '_wiki_page_actions'}/wiki_page_actions", :locals => { :page => page }
74
+ end
75
+
76
+ def wiki_page_history(page = nil,versions = nil)
77
+ page ||= @page # By default take page from instance variable
78
+ versions ||= page.versions
79
+
80
+ render :partial => "#{template_dir '_wiki_page_history'}/wiki_page_history", :locals => { :page => page, :versions => versions, :with_form => (versions.size > 1) }
81
+ end
82
+
83
+ end