fragmentary 0.1.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.
@@ -0,0 +1,53 @@
1
+ require 'rails/console/app'
2
+
3
+ module Fragmentary
4
+
5
+ class UserSession
6
+
7
+ include Rails::ConsoleMethods
8
+
9
+ attr_reader :session, :user
10
+
11
+ def initialize(*user, &block)
12
+ # app is from Rails::ConsoleMethods. It returns an object ActionDispatch::Integration::Session.new(Rails.application)
13
+ # with some extensions. See https://github.com/rails/rails/blob/master/railties/lib/rails/console/app.rb
14
+ # The session object has instance methods get, post etc.
15
+ # See https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/testing/integration.rb
16
+ @session = app
17
+ sign_in if @user = get_user(*user)
18
+ instance_eval(&block) if block_given?
19
+ end
20
+
21
+ def method_missing(method, *args)
22
+ session.send(method, *args)
23
+ end
24
+
25
+ def sign_out
26
+ post '/users/sign_out', {:_method => 'delete', :authenticity_token => request.session[:_csrf_token]}
27
+ end
28
+
29
+ def sign_in
30
+ get "/users/sign_in" # necessary in order to get the csrf token
31
+ # NOTE: In Rails 5, params is changed to a named argument, i.e. :params => {...}. Will need to be changed.
32
+ post "/users/sign_in", {:user => {:email => user.email, :password => user.try(:password)},
33
+ :authenticity_token => request.session[:_csrf_token]}
34
+ if session.redirect?
35
+ follow_redirect!
36
+ else
37
+ raise "Sign in failed for user #{user.name} #{user.password}"
38
+ end
39
+ end
40
+
41
+ private
42
+ def get_user(*attrs)
43
+ return nil if attrs.nil?
44
+ if (user = attrs.shift).is_a? User and user.password
45
+ user
46
+ elsif user.is_a? String
47
+ User.test_user(user, :admin => attrs.shift.try(:delete, :admin))
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,3 @@
1
+ module Fragmentary
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,56 @@
1
+ module Fragmentary
2
+
3
+ class Widget
4
+ attr_reader :template, :key, :match
5
+
6
+ def self.inherited subclass
7
+ super if defined? super
8
+ @subclasses ||= []
9
+ @subclasses << subclass
10
+ end
11
+
12
+ def self.subclasses
13
+ @subclasses ||= []
14
+ @subclasses.inject([]) do |list, subclass|
15
+ list.push(subclass, *subclass.subclasses)
16
+ end
17
+ end
18
+
19
+ def initialize(template, key)
20
+ @template = template
21
+ @key = key
22
+ @match = key.match(pattern)
23
+ end
24
+
25
+ def pattern
26
+ Regexp.new('^$')
27
+ end
28
+
29
+ def _content
30
+ match ? content : nil
31
+ end
32
+
33
+ def content
34
+ "Undefined Widget"
35
+ end
36
+ end
37
+
38
+
39
+ class UserWidget < Widget
40
+ attr_reader :current_user
41
+
42
+ def initialize(template, key)
43
+ super
44
+ @current_user = template.respond_to?(:current_user) ? template.current_user : nil
45
+ end
46
+
47
+ def _content
48
+ match ? user_content : nil
49
+ end
50
+
51
+ def user_content
52
+ current_user ? content : ""
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,46 @@
1
+ module Fragmentary
2
+
3
+ class WidgetParser
4
+
5
+ include ActionView::Helpers::JavaScriptHelper
6
+
7
+ attr_reader :template, :current_user, :widget_container
8
+
9
+ def initialize(template)
10
+ @template = template
11
+ @widget_container = {:'' => 'Empty widget specification detected'}
12
+ end
13
+
14
+ # This method returns a new OutputBuffer instance that can be used to overwrite the existing
15
+ # template's output_buffer with a copy that has its widget specifications expanded. It is
16
+ # usually called from cache_fragment to insert widgets into a cached root fragment. However
17
+ # when an ajax request inserts a non-root fragment into a page it can be invoked from
18
+ # CacheBuilder#cache_child if that method is called with the :insert_widgets option set to
19
+ # true. Alternatively if an ajax request inserts content containing a widget without a fragment
20
+ # context, i.e. in order to modify content *within* a fragment, a WidgetParser can be
21
+ # instantiated separately using erb at the end of the view template. This can be done either
22
+ # in an html template if the client is loading html by ajax (e.g. jQuery.load) or in a js(.coffee)
23
+ # script if the ajax request loads javascript.
24
+ def parse_buffer(options = {})
25
+ template.output_buffer.scan(/%{([^}]+)}/) do |spec|
26
+ widget_key = spec[0]; widget = nil
27
+ widget_container[widget_key.to_sym] = if Widget.subclasses.find{|klass| (widget = klass.new(template, widget_key)).match}
28
+ if options[:javascript] or options[:js]
29
+ escape_javascript(widget._content)
30
+ else
31
+ widget._content
32
+ end
33
+ else
34
+ "Oops! Widget not found."
35
+ end
36
+ end
37
+ # The gsub replaces instances of '%' that aren't part of widget specifications with '%%', preventing
38
+ # those characters from making the buffer an invalid format specification. The substitution operation
39
+ # restores them to single characters. The new OutputBuffer is needed because gsub returns a string.
40
+ # (Although gsub! would return an OutputBuffer if a substitution occurs, it returns nil otherwise,
41
+ # so isn't suitable here.)
42
+ ActionView::OutputBuffer.new(template.output_buffer.gsub(/%(?!{)/,'%%') % widget_container)
43
+ end
44
+ end
45
+
46
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fragmentary
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark Thomson
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-12-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 4.0.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5'
33
+ - !ruby/object:Gem::Dependency
34
+ name: delayed_job_active_record
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '4.1'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '4.1'
47
+ - !ruby/object:Gem::Dependency
48
+ name: wisper-activerecord
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.17'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.17'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.0'
103
+ description: Fragment caching for Rails with arbitrarily complex data dependencies
104
+ email:
105
+ - mark.thomson@persuasivethinking.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - ".gitignore"
111
+ - ".rspec"
112
+ - ".travis.yml"
113
+ - Gemfile
114
+ - LICENSE.txt
115
+ - README.md
116
+ - Rakefile
117
+ - bin/console
118
+ - bin/setup
119
+ - fragmentary.gemspec
120
+ - lib/fragmentary.rb
121
+ - lib/fragmentary/dispatcher.rb
122
+ - lib/fragmentary/fragment.rb
123
+ - lib/fragmentary/fragments_helper.rb
124
+ - lib/fragmentary/handler.rb
125
+ - lib/fragmentary/publisher.rb
126
+ - lib/fragmentary/request.rb
127
+ - lib/fragmentary/request_queue.rb
128
+ - lib/fragmentary/subscriber.rb
129
+ - lib/fragmentary/subscription.rb
130
+ - lib/fragmentary/user_session.rb
131
+ - lib/fragmentary/version.rb
132
+ - lib/fragmentary/widget.rb
133
+ - lib/fragmentary/widget_parser.rb
134
+ homepage: https://github.com/MarkMT/fragmentary
135
+ licenses:
136
+ - MIT
137
+ metadata: {}
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project:
154
+ rubygems_version: 2.4.8
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: Fragment modeling and caching for Rails
158
+ test_files: []