wrap_it 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/.yardopts +3 -0
  4. data/README.md +67 -66
  5. data/lib/wrap_it.rb +16 -16
  6. data/lib/wrap_it/arguments.rb +368 -0
  7. data/lib/wrap_it/base.rb +56 -47
  8. data/lib/wrap_it/callbacks.rb +24 -5
  9. data/lib/wrap_it/capture_array.rb +140 -0
  10. data/lib/wrap_it/container.rb +69 -25
  11. data/lib/wrap_it/derived_attributes.rb +22 -6
  12. data/lib/wrap_it/enums.rb +44 -34
  13. data/lib/wrap_it/frameworks.rb +7 -3
  14. data/lib/wrap_it/helpers.rb +66 -1
  15. data/lib/wrap_it/html.rb +149 -0
  16. data/lib/wrap_it/html_class.rb +164 -183
  17. data/lib/wrap_it/html_data.rb +28 -15
  18. data/lib/wrap_it/link.rb +40 -17
  19. data/lib/wrap_it/sections.rb +90 -2
  20. data/lib/wrap_it/switches.rb +33 -29
  21. data/lib/wrap_it/text_container.rb +83 -10
  22. data/lib/wrap_it/version.rb +2 -1
  23. data/spec/frameworks/log/development.log +2108 -0
  24. data/spec/integration/base_spec.rb +2 -2
  25. data/spec/integration/container_spec.rb +3 -3
  26. data/spec/integration/examples_spec.rb +16 -15
  27. data/spec/integration/text_container_spec.rb +3 -3
  28. data/spec/lib/arguments_array_spec.rb +37 -27
  29. data/spec/lib/arguments_spec.rb +153 -0
  30. data/spec/lib/base_spec.rb +2 -25
  31. data/spec/lib/callbacks_spec.rb +1 -1
  32. data/spec/lib/container_spec.rb +1 -1
  33. data/spec/lib/derived_attributes_spec.rb +1 -1
  34. data/spec/lib/enums_spec.rb +2 -3
  35. data/spec/lib/html_class_spec.rb +269 -80
  36. data/spec/lib/html_data_spec.rb +18 -12
  37. data/spec/lib/html_spec.rb +124 -0
  38. data/spec/lib/link_spec.rb +2 -2
  39. data/spec/lib/sections_spec.rb +1 -1
  40. data/spec/lib/switches_spec.rb +3 -3
  41. data/spec/lib/text_container_spec.rb +2 -2
  42. data/spec/support/example_groups/{wrap_it_example_group.rb → wrapped_example_group.rb} +5 -5
  43. data/wrap_it.gemspec +2 -0
  44. metadata +15 -8
  45. data/lib/wrap_it/arguments_array.rb +0 -128
  46. data/lib/wrap_it/module_helpers.rb +0 -23
@@ -5,33 +5,49 @@ module WrapIt
5
5
  # @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
6
6
  #
7
7
  module DerivedAttributes
8
+ # Documentation includes
9
+ # @!parse extend DerivedAttributes::ClassMethods
10
+
11
+ # module implementation
12
+
13
+ #
8
14
  def self.included(base)
9
15
  base.extend ClassMethods
10
16
  end
11
17
 
12
18
  #
13
- # Class methods to include
19
+ # {DerivedAttributes} class methods
14
20
  #
15
21
  module ClassMethods
22
+ #
23
+ # retrieves first founded derived variable or nil
24
+ # @param name [Symbol] variable name (should contain `@` sign)
25
+ #
26
+ # @return [Object, nil] founded variable or nil
16
27
  def get_derived(name)
17
28
  return instance_variable_get(name) if instance_variable_defined?(name)
18
29
  ancestors.each do |ancestor|
19
- break if ancestor == Object
20
30
  next unless ancestor.instance_variable_defined?(name)
31
+ break if ancestor == Base
21
32
  return ancestor.instance_variable_get(name)
22
33
  end
23
34
  nil
24
35
  end
25
36
 
37
+ #
38
+ # Collects all derived variables with specified name
39
+ # @param name [Symbol] variable name (should contain `@` sign)
40
+ # @param initial [Object] initial collection object
41
+ # @param method [Symbol] collection's method name to concatinate
42
+ # founded variable with collection
43
+ #
44
+ # @return [Object] collection of variables
26
45
  def collect_derived(name, initial = [], method = :concat)
27
46
  result = initial
28
- # if instance_variable_defined?(name)
29
- # result = result.send(method, instance_variable_get(name))
30
- # end
31
47
  ancestors.each do |ancestor|
32
- break if ancestor == Object
33
48
  next unless ancestor.instance_variable_defined?(name)
34
49
  result = result.send(method, ancestor.instance_variable_get(name))
50
+ break if ancestor == Base
35
51
  end
36
52
  result
37
53
  end
data/lib/wrap_it/enums.rb CHANGED
@@ -5,47 +5,38 @@ module WrapIt
5
5
  # @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
6
6
  #
7
7
  module Enums
8
+ # Documentation includes
9
+ # @!parse extend Enums::ClassMethods
10
+
11
+ # module implementation
12
+
8
13
  extend DerivedAttributes
9
14
 
15
+ #
10
16
  def self.included(base)
11
17
  base == Base || fail(
12
18
  TypeError,
13
19
  "#{self.class.name} can be included only into WrapIt::Base"
14
20
  )
15
- base.extend ClassMethods
16
- base.after_initialize :enums_init
17
- end
21
+ base.class_eval do
22
+ extend ClassMethods
18
23
 
19
- private
24
+ before_initialize { @enums = {} }
20
25
 
21
- def enums_init
22
- @enums = {}
23
- opt_keys = @options.keys
24
- enums.each do |name, opts|
25
- value = nil
26
- names = [name] + [opts[:aliases] || []].flatten
27
- opt_keys.select { |o| names.include? o }.each do |key|
28
- tmp = @options.delete(key)
29
- value ||= tmp
30
- !value.nil? && !opts[:values].include?(value) && value = nil
31
- end
32
- @arguments.extract!(Symbol, and: [opts[:values]]).each do |key|
33
- value ||= key
26
+ before_capture do
27
+ self.class.collect_derived(:@enums, {}, :merge).each do |name, e|
28
+ next unless e.key?(:default) && !@enums.key?(name)
29
+ send("#{name}=", e[:default])
30
+ end
34
31
  end
35
- send("#{name}=", value)
36
32
  end
37
33
  end
38
34
 
39
- def enums
40
- @enums_hash ||= self.class.collect_derived(:@enums, {}, :merge)
41
- end
42
-
43
35
  #
44
- # Class methods to include
36
+ # {Enums} class methods
45
37
  #
46
38
  module ClassMethods
47
39
  #
48
- # @dsl
49
40
  # Adds `enum`. When element created, creation arguments will be scanned
50
41
  # for `Symbol`, that included contains in `values`. If it founded, enum
51
42
  # takes this value. Also creation options inspected. If its contains
@@ -60,16 +51,26 @@ module WrapIt
60
51
  #
61
52
  # This method also adds getter and setter for this enum.
62
53
  #
54
+ # @example
55
+ # class Button < WrapIt::Base
56
+ # enum :style, %i(red green black), html_class_prefix: 'btn-'
57
+ # end
58
+ #
59
+ # btn = Button.new(template, :green)
60
+ # btn.render # => '<div class="btn-green">'
61
+ # btn = Button.new(template, style: :red)
62
+ # btn.render # => '<div class="btn-red">'
63
+ #
63
64
  # @param name [String, Symbol] Enum name. Converted to `Symbol`.
64
- # @param options [Hash] Enum options
65
- # @options options [String, Symbol] :html_class_prefix prefix of HTML
65
+ # @param opts [Hash] Enum options
66
+ # @option opts [String, Symbol] :html_class_prefix prefix of HTML
66
67
  # class that will automatically added to element if enum changes its
67
68
  # value.
68
- # @options options [Boolean] :html_class whether this enum changes
69
+ # @option opts [Boolean] :html_class whether this enum changes
69
70
  # should affect to html class.
70
- # @options options [Symbol, Array<Symbol>] :aliases list of enum aliases.
71
+ # @option opts [Symbol, Array<Symbol>] :aliases list of enum aliases.
71
72
  # Warning! Values are not converted - pass only `Symbols` here.
72
- # @options options [String, Symbol] :default default value for enum,
73
+ # @option opts [String, Symbol] :default default value for enum,
73
74
  # if nil or wrong value given. Converted to `Symbol`.
74
75
  # @yield [value] Runs block when enum value changed, gives it to block.
75
76
  # @yieldparam value [Symbol] New enum value.
@@ -90,25 +91,34 @@ module WrapIt
90
91
  opts[:regexp] = /\A#{prefix}(?:#{values.join('|')})\z/
91
92
  opts[:html_class_prefix] = prefix
92
93
  end
93
- define_method("#{name}") { @enums[name] }
94
+ define_method("#{name}") { @enums[name] ||= opts[:default] }
94
95
  define_method("#{name}=", &Enums.setter(name, &block))
95
96
  @enums ||= {}
97
+
98
+ o_params = {}
99
+ if opts.key?(:aliases)
100
+ aliases = [opts[:aliases]].flatten.compact
101
+ o_params[:if] = [name] + aliases
102
+ end
103
+
96
104
  @enums[name] = opts
105
+ option(name, **o_params) { |_, v| send("#{name}=", v) }
106
+ argument(name, if: Symbol, and: values) { |_, v| send("#{name}=", v) }
97
107
  end
98
108
  end
99
109
 
100
110
  private
101
111
 
102
112
  def self.setter(name, &block)
103
- proc do |value|
104
- opts = enums[name]
113
+ ->(value) do
114
+ opts = self.class.collect_derived(:@enums, {}, :merge)[name]
105
115
  v = value if opts[:values].include?(value)
106
116
  v ||= opts[:default] if opts.key?(:default)
107
117
  @enums[name] = v
108
118
  block.nil? || instance_exec(v, &block)
109
119
  if opts.key?(:regexp)
110
- remove_html_class(opts[:regexp])
111
- v.nil? || add_html_class("#{opts[:html_class_prefix]}#{v}")
120
+ html_class.delete(opts[:regexp])
121
+ v.nil? || html_class << "#{opts[:html_class_prefix]}#{v}"
112
122
  end
113
123
  end
114
124
  end
@@ -1,7 +1,9 @@
1
- #
2
- # Framework detection methods
3
- #
4
1
  module WrapIt
2
+ #
3
+ # Framework detection methods
4
+ #
5
+
6
+ # @private
5
7
  def self.framework
6
8
  return @framework unless @framework.nil?
7
9
  gems = Gem.loaded_specs.keys
@@ -14,10 +16,12 @@ module WrapIt
14
16
  end
15
17
  end
16
18
 
19
+ # @private
17
20
  def self.rails?
18
21
  framework == :rails
19
22
  end
20
23
 
24
+ # @private
21
25
  def self.sinatra?
22
26
  framework == :sinatra
23
27
  end
@@ -1,9 +1,64 @@
1
1
  #
2
- # Helper registering
2
+ # Registering helpers
3
+ #
4
+ # To use your classes and helpers in templates you should register your
5
+ # library. First, in your framework initialization, you should register
6
+ # your library in WrapIt. You can have separate module for it or WrapIt
7
+ # will make anonymous one. After this, your module will have `register`
8
+ # and `unregister` methods to register your classes.
9
+ #
10
+ # @example usual case - library in separate module
11
+ # # initialization time
12
+ # module Library
13
+ # module Helpers; end
14
+ # end
15
+ # WrapIt.register_module Library::Helpers, prefix: 'lib_'
16
+ #
17
+ # # controller
18
+ # class MyController < ApplicationController
19
+ # helper Library::Helpers
20
+ # end
21
+ #
22
+ # # implementation
23
+ # module Library
24
+ # module Helpers
25
+ # class Button < WrapIt::Base
26
+ # ...
27
+ # end
28
+ #
29
+ # register :super_button, Button
30
+ # end
31
+ # end
32
+ #
33
+ # # in template:
34
+ # <%= lib_super_button 'text' %>
35
+ #
36
+ # @example anonymous module
37
+ # helpers = WrapIt.register_module prefix: 'lib_'
38
+ #
39
+ # class Button < WrapIt::Base
40
+ # ...
41
+ # end
42
+ #
43
+ # helpers.register :super_button, Button
44
+ #
45
+ # class MyController
46
+ # helper helpers
47
+ # end
3
48
  #
4
49
  # @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
5
50
  #
6
51
  module WrapIt
52
+ #
53
+ # Registers helpers module
54
+ #
55
+ # @overload register_module(mod = nil, opts = {})
56
+ # @param mod [Module] module for register. Anonymous module will be
57
+ # created if ommited.
58
+ # @param opts [Hash] options
59
+ # @option opts [String] :prefix prefix for helper methods
60
+ #
61
+ # @return [void]
7
62
  def self.register_module(*args)
8
63
  options = args.extract_options!
9
64
  options.symbolize_keys!
@@ -17,6 +72,16 @@ module WrapIt
17
72
  mod
18
73
  end
19
74
 
75
+ # @!method register([name, ...], class_name)
76
+ # adds to template list of helpers for creating elements of specified class
77
+ # @param name [Symbol, String] name of helper. Will be prefixed with prefix
78
+ # option, specified in {WrapIt#register_module} call.
79
+ # @param class_name [String, Class] element class
80
+
81
+ # @!method unregister([name, ...])
82
+ # removes list of helpers from template
83
+ # @param name [Symbol, String] name of helper to remove from tampate
84
+
20
85
  private
21
86
 
22
87
  def self.register_block(options)
@@ -0,0 +1,149 @@
1
+ require File.join %w(wrap_it html_class)
2
+ require File.join %w(wrap_it html_data)
3
+
4
+ module WrapIt
5
+ #
6
+ # Methods for manipulationg with HTML class. For internal usage.
7
+ # You should not include this class directly - subclass from
8
+ # `WrapIt::Base` instead.
9
+ #
10
+ # @author Alexey Ovchinnikov <alexiss@cybernetlab.ru>
11
+ #
12
+ module HTML
13
+ # Documentation includes
14
+ # @!parse extend HTML::ClassMethods
15
+
16
+ # module implementation
17
+
18
+ extend DerivedAttributes
19
+
20
+ #
21
+ def self.included(base)
22
+ base == Base || fail(
23
+ TypeError,
24
+ "#{self.class.name} can be included only into WrapIt::Base"
25
+ )
26
+ base.class_eval do
27
+ extend ClassMethods
28
+
29
+ option(:class) { |_, v| self.html_class << v }
30
+
31
+ # TODO: extend hashes for html_attr and html_data
32
+ before_initialize do
33
+ html_class
34
+ @html_attr ||= {}
35
+ @html_data ||= {}
36
+ end
37
+ end
38
+ end
39
+
40
+ # TODO: actually we should have separate setter and merge (see Base)
41
+ #
42
+ # Sets HTML attributes hash.
43
+ #
44
+ # Actually it merges its with current
45
+ # attributes. To remove some attributes use `html_attr.delete(:attr)`.
46
+ # extracts HTML class and data from provided hash and places its to
47
+ # appropriate holder
48
+ #
49
+ # @param hash [Hash] attributes
50
+ #
51
+ # @return [Hash] resulting attributes
52
+ def html_attr=(hash)
53
+ return unless hash.is_a?(Hash)
54
+ hash.symbolize_keys!
55
+ html_class << hash.delete(:class)
56
+ html_data.merge(hash.delete(:data) || {})
57
+ (@html_attr ||= {}).merge!(hash)
58
+ end
59
+
60
+ #
61
+ # Retrieves HTML attributes hash (without HTML class and HTML data)
62
+ #
63
+ # @return [Hash] attributes
64
+ def html_attr
65
+ @html_attr ||= {}
66
+ end
67
+
68
+ #
69
+ # Retrieves HTML data hash
70
+ #
71
+ # @return [Hash] data
72
+ def html_data
73
+ @html_data ||= {}
74
+ end
75
+
76
+ #
77
+ # HTML class prefix getter
78
+ #
79
+ # This prefix used in enums to combine HTML classes.
80
+ #
81
+ # @return [String] HTML class prefix.
82
+ def html_class_prefix
83
+ @html_class_prefix ||= self.class.html_class_prefix
84
+ end
85
+
86
+ #
87
+ # Sets HTML class(es) for element
88
+ #
89
+ # @example
90
+ # element.html_class = [:a, 'b', ['c', :d, 'a']]
91
+ # element.html_class #=> ['a', 'b', 'c', 'd']
92
+ #
93
+ # @param value [Symbol, String, Array<Symbol, String>] HTML class or list
94
+ # of classes. All classes will be converted to Strings, duplicates are
95
+ # removed. Refer to {HTMLClass} description for details.
96
+ # @return [HTMLClass] resulting html class
97
+ def html_class=(value)
98
+ @html_class = HTMLClass.new(value)
99
+ end
100
+
101
+ #
102
+ # Retrieves HTML class of element
103
+ #
104
+ # See {HTMLClass} for details
105
+ #
106
+ # @return [HTMLClass] HTML class of element
107
+ def html_class
108
+ @html_class ||= HTMLClass.new
109
+ end
110
+
111
+ protected
112
+
113
+ def add_default_classes
114
+ html_class << self.class.collect_derived(
115
+ :@html_class, HTMLClass.new, :<<
116
+ )
117
+ end
118
+
119
+ #
120
+ # {HTML} class methods
121
+ #
122
+ module ClassMethods
123
+ #
124
+ # Adds default html classes, thats are automatically added when element
125
+ # created.
126
+ # @overload html_class([html_class, ...])
127
+ # @param html_class [String, Symbol, Array<String, Symbol>] HTML class.
128
+ # Converted to `String`
129
+ #
130
+ # @return [void]
131
+ def html_class(*args)
132
+ (@html_class ||= HTMLClass.new) << args
133
+ end
134
+
135
+ #
136
+ # Sets HTML class prefix. It used in switchers and enums
137
+ # @param prefix [String] HTML class prefix
138
+ #
139
+ # @return [void]
140
+ def html_class_prefix(prefix = nil)
141
+ return(get_derived(:@html_class_prefix) || '') if prefix.nil?
142
+ prefix.is_a?(Symbol) && prefix = prefix.to_s
143
+ prefix.is_a?(String) || fail(ArgumentError,
144
+ 'prefix should be a String or Symbol')
145
+ @html_class_prefix = prefix
146
+ end
147
+ end
148
+ end
149
+ end