Class: String

Inherits:
Object show all
Defined in:
lib/util/ext/blank.rb,
lib/util/inflect.rb,
lib/util/ext/string.rb,
lib/sync/stroke_diff/string.rb

Overview

extracted and adapted from ActiveRecord (rubyforge.org/projects/activesupport/)

Direct Known Subclasses

StrokeDB::DocumentReferenceValue

Instance Method Summary collapse

Instance Method Details

#blank?Boolean



41
42
43
# File 'lib/util/ext/blank.rb', line 41

def blank?
  self !~ /\S/
end

#camel_caseObject Also known as: camelize



9
10
11
# File 'lib/util/ext/string.rb', line 9

def camel_case
  split('_').map{|e| e.capitalize}.join
end

#constantizeObject



28
29
30
31
32
33
34
# File 'lib/util/ext/string.rb', line 28

def constantize
  unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
    raise NameError, "#{self.inspect} is not a valid constant name!"
  end

  Object.module_eval("::#{$1}", __FILE__, __LINE__)
end

#demodulizeObject



24
25
26
# File 'lib/util/ext/string.rb', line 24

def demodulize
  gsub(/^.*::/, '')
end

#ends_with?(suffix) ⇒ Boolean



4
5
6
7
# File 'lib/util/ext/string.rb', line 4

def ends_with?(suffix)
  suffix = suffix.to_s
  self[-suffix.length, suffix.length] == suffix
end

#pluralObject Also known as: pluralize



213
214
215
# File 'lib/util/inflect.rb', line 213

def plural
  English::Inflect.plural(self)
end

#singularObject Also known as: singularize



208
209
210
# File 'lib/util/inflect.rb', line 208

def singular
  English::Inflect.singular(self)
end

#snake_caseObject



14
15
16
# File 'lib/util/ext/string.rb', line 14

def snake_case
  gsub(/\B[A-Z][^A-Z]/, '_\&').downcase.gsub(' ', '_')
end

#stroke_diff(to) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/sync/stroke_diff/string.rb', line 3

def stroke_diff(to)
  return super(to) unless String === to
  return nil if self == to
  
  _f = self[0,2]
  _t = to[0,2]
  pfx = "@#"
  # both are refs
  return super(to) if _f == _t && _t == pfx
  # one of items is ref, another is not.
  return super(to) if _f == pfx || _t == pfx
        
  lcs_diff = ::Diff::LCS.diff(self, to)
  patchset = lcs_diff.map do |changes| 
    parts = []
    last_part = changes.inject(nil) do |part, change|
      if part && part[0] == change.action && part[3] == change.position - 1
        part[3] += 1
        part[2] << change.element
        part
      else
        parts << part if part
        # emit
        [change.action, change.position, change.element, change.position]
      end
    end
    parts << last_part if last_part
    parts.empty? ? nil : parts
  end.compact.inject([]) do |patches, ps|
    ps.map do |p|
      patches << if p[0] == '+'
        [PATCH_PLUS,  p[1], p[2]]      # [+  position_in_b  substr]
      else
        [PATCH_MINUS, p[1], p[2].size] # [-  position_in_a  length]
      end
    end
    patches
  end
  #p patchset
  patchset.empty? ? nil : patchset
end

#stroke_merge(patch1, patch2) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/sync/stroke_diff/string.rb', line 81

def stroke_merge(patch1, patch2)
  # One patch is missing (i.e. no changes)
  unless patch1 && patch2
    return _stroke_automerged(stroke_patch(patch1 || patch2))
  end

  # Patch could be either PATCH_REPLACE or regular string diff.
  # Thus, 4 cases:
  #
  # [replace, replace] -> possible conflict
  # [replace, diff]    -> conflict
  # [diff,    replace] -> conflict
  # [diff,    diff]    -> possible conflict

  # Code is verbose to be fast and clear
  if patch1[0] == PATCH_REPLACE
    if patch2[0] == PATCH_REPLACE # [replace, replace]
      if patch1[1] != patch2[1]
        return _stroke_conflicted(stroke_patch(patch1), stroke_patch(patch2))
      else
        return _stroke_automerged(stroke_patch(patch1))
      end
    else # [replace, diff]
       return _stroke_conflicted(stroke_patch(patch1), stroke_patch(patch2))
    end
  else
    if patch1[0] == PATCH_REPLACE # [diff, replace]
      return _stroke_conflicted(stroke_patch(patch1), stroke_patch(patch2))
    else
      nil # [diff, diff] - see below
    end
  end
	  # TODO: ...
end

#stroke_patch(patch) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/sync/stroke_diff/string.rb', line 45

def stroke_patch(patch)
  return self unless patch
  return patch[1] if patch[0] == PATCH_REPLACE
  
  # Patch is a list of insertions and deletions.
  # Deletion is indexed relative to base.
  # Insertion is indexed relative to new string.
  res = ""
  ai = bj = 0
  patch.each do |change|
    action, position, element = change
    case action
    when PATCH_MINUS
      d = position - ai
      if d > 0
        res << self[ai, d]
        ai += d
        bj += d
      end
      ai += element # element == length
    when PATCH_PLUS
      d = position - bj
      if d > 0
        res << self[ai, d]
        ai += d
        bj += d
      end
      bj += element.size
      res << element
    end
  end
  d = self.size - ai
  res << self[ai, d] if d > 0
  res
end

#tableizeObject



18
19
20
21
22
# File 'lib/util/ext/string.rb', line 18

def tableize
  words = snake_case.split('_')
  words.last.replace words.last.plural
  words.join('_')
end