irwi 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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