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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +53 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/app/views/base_wiki_pages/_wiki_page_actions.html.erb +4 -0
- data/app/views/base_wiki_pages/_wiki_page_history.html.erb +31 -0
- data/app/views/base_wiki_pages/_wiki_page_info.html.erb +3 -0
- data/app/views/base_wiki_pages/_wiki_page_style.html.erb +69 -0
- data/app/views/base_wiki_pages/compare.html.erb +13 -0
- data/app/views/base_wiki_pages/edit.html.erb +14 -0
- data/app/views/base_wiki_pages/history.html.erb +7 -0
- data/app/views/base_wiki_pages/no.html.erb +1 -0
- data/app/views/base_wiki_pages/not_allowed.html.erb +1 -0
- data/app/views/base_wiki_pages/show.html.erb +10 -0
- data/generators/irwi_wiki/irwi_wiki_generator.rb +22 -0
- data/generators/irwi_wiki/templates/controllers/wiki_pages_controller.rb +5 -0
- data/generators/irwi_wiki/templates/helpers/wiki_pages_helper.rb +3 -0
- data/generators/irwi_wiki/templates/migrate/create_wiki_pages.rb +44 -0
- data/generators/irwi_wiki/templates/models/wiki_page.rb +5 -0
- data/generators/irwi_wiki/templates/models/wiki_page_version.rb +5 -0
- data/irwi.gemspec +99 -0
- data/lib/irwi.rb +7 -0
- data/lib/irwi/comparators/base.rb +17 -0
- data/lib/irwi/comparators/diff_lcs.rb +52 -0
- data/lib/irwi/comparators/spans/changed_span.rb +18 -0
- data/lib/irwi/comparators/spans/not_changed_span.rb +20 -0
- data/lib/irwi/config.rb +18 -0
- data/lib/irwi/extensions/controllers/wiki_pages.rb +123 -0
- data/lib/irwi/extensions/models/wiki_page.rb +46 -0
- data/lib/irwi/extensions/models/wiki_page_version.rb +40 -0
- data/lib/irwi/formatters/blue_cloth.rb +11 -0
- data/lib/irwi/formatters/red_cloth.rb +11 -0
- data/lib/irwi/helpers/wiki_pages_helper.rb +83 -0
- data/lib/irwi/support/route_mapper.rb +17 -0
- data/lib/irwi/support/template_finder.rb +11 -0
- data/rails/init.rb +31 -0
- data/spec/comparators/diff_lcs_spec.rb +37 -0
- data/spec/config_spec.rb +58 -0
- data/spec/extensions/controllers/wiki_pages_spec.rb +53 -0
- data/spec/helpers/wiki_pages_helper_spec.rb +74 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/route_mapper_spec.rb +20 -0
- data/spec/support/template_finder_spec.rb +33 -0
- data/tasks/riwiki_tasks.rake +4 -0
- metadata +127 -0
data/lib/irwi.rb
ADDED
@@ -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
|
data/lib/irwi/config.rb
ADDED
@@ -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,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 '<Unknown>' 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
|